diff --git a/.specstory/history/2026-02-18_23-39Z-character-migrator-workflow-integration.md b/.specstory/history/2026-02-18_23-39Z-character-migrator-workflow-integration.md index e63f38c..7644a1d 100644 --- a/.specstory/history/2026-02-18_23-39Z-character-migrator-workflow-integration.md +++ b/.specstory/history/2026-02-18_23-39Z-character-migrator-workflow-integration.md @@ -8962,7 +8962,1240 @@ The user wants me to implement the NLAMig enhancements plan. Let me read the pla 4. Preserve full strip timing/effects (action_frame_start/end, influence, mute, scale, use_* flags) 5. Order: no anim_data return → active-action-only path → NLA path (add tracks) → mirror als.turn_on -I need to check if there are todos in the plan - the user said "To-do's from +I need to check if there are todos in the plan - the user said "To-do's from the plan have already been created" but the plan file shows `todos: []`. I'll proceed with implementation and mark todos if I find them. + +Let me read the current migrator.py run_step_2 and implement the changes. + + +--- + + +Implementing the NLAMig enhancements: reading the migrator and plan, then applying the changes. + + +--- + + +
Tool use: **read_file_v2** • Read file: T:\Dynamic-Link-Manager\ops\migrator.py + +
+
+ +--- + + +
+Tool use: **glob_file_search** • Searched codebase "undefined" • **0** result in **1** directory + +Directory: **T:\Dynamic-Link-Manager** (0 file) + +
+
+ +--- + +
Thought Process + +No plan file in workspace. I'll implement directly. I need to: + +1. Add `_mirror_als_turn_on(orig, rep)` helper that copies "als.turn_on" from orig to rep (object level, and optionally bone level if we can find it). +2. Refactor `run_step_2`: + - If no orig.animation_data: return + - If orig.animation_data exists but nla_tracks is empty and action is set: ensure rep.animation_data, set rep.animation_data.action = orig.animation_data.action, _mirror_als_turn_on(orig, rep), return + - Else (NLA path): ensure rep.animation_data, do NOT remove tracks + - For each track in orig: add new track (uniquify name if rep already has it), copy track props, for each strip copy all properties + - Copy strip: action, frame_start, frame_end, blend_type, extrapolation, blend_in, blend_out, repeat, action_frame_start, action_frame_end, influence, mute, scale, use_auto_blend, use_reverse, use_animated_influence, use_animated_time, use_animated_time_cyclic, use_sync_length + - At end: _mirror_als_turn_on(orig, rep) + +Blender's NlaStrips.new(name, start_frame, action) - then we need to set frame_end and other props. Some props might be read-only after creation; I'll set what's writable. + +Let me implement. For _mirror_als_turn_on: try orig.get("als.turn_on") on the object. If the addon stores on a bone, we could try common bone names like "root" or the first bone - but the plan says "armature object (e.g. orig["als.turn_on"])" and "if the addon stores it on a specific bone, check that bone on orig and mirror to the same bone on rep". So: first try object level; then try pose bones (iterate and check for "als.turn_on" on any bone). If found on orig, set on rep in same location. +
+ +--- + + +Implementing the plan: adding `_mirror_als_turn_on` and refactoring `run_step_2`. + + +--- + + +
Tool use: **todo_write** • Todo List + +- [-] Add _mirror_als_turn_on(orig, rep) helper +- [ ] Active-action-only path + add-only NLA + full strip props +- [x] Add Tweak Tools box and rows to panels.py +- [x] Add 9 tweak operators and register in operators.py + +
+
+ +--- + +
Thought Process + +I'll add the helper and refactor run_step_2 in one go. First add _mirror_als_turn_on, then replace run_step_2 body. +
+ +--- + + + + + +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ops\migrator.py + +
+ +
+ +--- + +
Thought Process + +Implementation is in. Let me verify: (1) NlaStrips.new() - in Blender 4.x/5 the signature might be (name, start, end, action) or (name, start, action). I used (strip.name, int(strip.frame_start), strip.action) which matches the original code. (2) Only CLIP strips with an action are copied - avoids errors for META/TRANSITION/SOUND. (3) I'll check lints and mark todos. +
+ +--- + + + + + +--- + + +
+Tool use: **read_lints** + + +Parameters: + +```json +{ + "paths": [ + "T:\\Dynamic-Link-Manager\\ops\\migrator.py" + ] +} +``` +Result: + +```json +{ + "linterErrorsByFile": [ + { + "relativeWorkspacePath": "T:\\Dynamic-Link-Manager\\ops\\migrator.py" + } + ] +} +``` +Status: **completed** + + +
+
+ +--- + + +
Tool use: **todo_write** • Todo List + +- [x] Add _mirror_als_turn_on(orig, rep) helper +- [-] Active-action-only path + add-only NLA + full strip props +- [x] Add Tweak Tools box and rows to panels.py +- [x] Add 9 tweak operators and register in operators.py + +
+
+ +--- + +
Thought Process + +All implementation is done in one edit. Let me mark todo 2 completed and double-check the code for any Blender API quirks. In Blender, NlaStrips.new(name, start_frame, action) - I need to confirm the order. From the Blender docs, NlaStrips.new(name, start, end, action) in some versions, or (name, start, action). Let me check the original code: new_track.strips.new(strip.name, int(strip.frame_start), strip.action) - so it's (name, frame_start, action). Good. + +One potential issue: when we do `rep_tracks.new(prev=prev_track)`, the new track is inserted after prev_track. So the first time, prev_track is the last existing track (or None). Then we set prev_track = new_track for the next iteration. So new tracks are appended in order. Good. + +I'll mark the second todo completed. +
+ +--- + + + + + +--- + + +
Tool use: **todo_write** • Todo List + +- [x] Add _mirror_als_turn_on(orig, rep) helper +- [x] Active-action-only path + add-only NLA + full strip props +- [x] Add Tweak Tools box and rows to panels.py +- [x] Add 9 tweak operators and register in operators.py + +
+
+ +--- + +
Thought Process + +All todos from the plan are done. Let me provide a short summary to the user. +
+ +--- + + +Summary of what was implemented in [ops/migrator.py](T:\Dynamic-Link-Manager\ops\migrator.py): + +**1. `_mirror_als_turn_on(orig, rep)`** +- Copies `"als.turn_on"` from the original to the replacement: first on the armature object, then on any pose bone that has the property (same bone name on `rep`). + +**2. Active-action-only path** +- If `orig` has `animation_data`, no NLA tracks, and an active `action`, the step no longer runs full NLA migration. It ensures `rep` has `animation_data`, sets `rep.animation_data.action = orig.animation_data.action`, runs `_mirror_als_turn_on`, and returns. + +**3. Add-only NLA (no replace)** +- Existing NLA tracks on `rep` are left in place. For each track on `orig`, a new track is added after the last track (existing or newly added). If the track name already exists on `rep`, it is uniquified (e.g. `Name.001`, `Name.002`). + +**4. Strip timing and effects** +- Only `CLIP` strips with an `action` are migrated. For each such strip we copy: + - Existing: `frame_start`, `frame_end`, `blend_type`, `extrapolation`, `blend_in`, `blend_out`, `repeat` + - New: `action_frame_start`, `action_frame_end`, `influence`, `mute`, `scale`, `use_auto_blend`, `use_reverse`, `use_animated_influence`, `use_animated_time`, `use_animated_time_cyclic`, `use_sync_length` + +**5. Order of operations** +- No `orig.animation_data` → return. +- NLA tracks empty and active action set → apply action, mirror `als.turn_on`, return. +- Otherwise → ensure `rep.animation_data`, add new tracks (with name uniquify), copy track and strip props, then call `_mirror_als_turn_on(orig, rep)`. + +All related todos are completed. No linter issues reported. + +--- + +_**User**_ + +Add documentation to all operators drawn in the UI that don't already have them. No operators should be named step1 step2, etc. They should all follow a naming convention along the lines of the true names of the operators: CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys. + +--- + +_**Agent (model default, mode Agent)**_ + + + +--- + +
Thought Process + +The user wants me to: +1. Add documentation to all operators that are drawn in the UI but don't already have documentation +2. Ensure no operators are named step1, step2, etc. - they should follow a naming convention like: CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys + +I'm in plan mode, so I need to research the codebase to understand: +- Where operators are defined and which ones are "drawn in the UI" +- Which operators already have documentation vs which don't +- Which operators have generic names like step1, step2 that need to be renamed +- The naming convention to apply + +Let me search for operators in the codebase, especially in ui/operators.py and any UI drawing code. +
+ +--- + + +Searching the codebase for operators drawn in the UI and their documentation/naming. + + +--- + + +
Tool use: **read_file_v2** • Read file: T:\Dynamic-Link-Manager\ui\operators.py + +
+
+ +--- + + +
+Tool use: **ripgrep_raw_search** + + +Parameters: + +```json +{ + "pattern": "step\\d|step1|step2|step3", + "path": "T:\\Dynamic-Link-Manager", + "caseInsensitive": false +} +``` +Additional data: + +```json +{ + "isPruned": true, + "pattern": "step\\d|step1|step2|step3", + "path": "T:\\Dynamic-Link-Manager", + "outputMode": "content", + "totalFiles": 4, + "totalMatches": 30, + "topFiles": [ + { + "uri": "ops\\migrator.py", + "matchCount": 9 + }, + { + "uri": ".specstory\\history\\2026-02-18_23-39Z-character-migrator-workflow-integration.md", + "matchCount": 6 + }, + { + "uri": "ops/migrator.py", + "matchCount": 9 + }, + { + "uri": ".specstory/history/2026-02-18_23-39Z-character-migrator-workflow-integration.md", + "matchCount": 6 + } + ] +} +``` +Status: **completed** + + +
+
+ +--- + + +
+Tool use: **ripgrep_raw_search** + + +Parameters: + +```json +{ + "pattern": "bl_idname|bl_label|bl_description", + "path": "T:\\Dynamic-Link-Manager", + "caseInsensitive": false +} +``` +Additional data: + +```json +{ + "isPruned": true, + "pattern": "bl_idname|bl_label|bl_description", + "path": "T:\\Dynamic-Link-Manager", + "outputMode": "content", + "totalFiles": 9, + "totalMatches": 274, + "topFiles": [ + { + "uri": "ui\\operators.py", + "matchCount": 60 + }, + { + "uri": ".specstory/history/2025-08-20_22-43Z-creating-a-blender-extension-for-asset-replacement.md", + "matchCount": 100 + }, + { + "uri": ".specstory/history/2026-02-18_23-39Z-character-migrator-workflow-integration.md", + "matchCount": 25 + }, + { + "uri": "ui/preferences.py", + "matchCount": 1 + }, + { + "uri": "ui\\panels.py", + "matchCount": 1 + }, + { + "uri": "ui/operators.py", + "matchCount": 60 + }, + { + "uri": "ui/panels.py", + "matchCount": 1 + }, + { + "uri": ".specstory\\history\\2026-02-18_23-39Z-character-migrator-workflow-integration.md", + "matchCount": 25 + }, + { + "uri": "__init__.py", + "matchCount": 1 + } + ] +} +``` +Status: **completed** + + +
+
+ +--- + +
Thought Process + +I need to: +1. Find all operators that are drawn in the UI (which panels draw which operators) +2. Check which operators have bl_description (documentation) and which don't +3. Check if any operators use step1/step2 style names - the grep showed migrator operators use names like migrator_copy_attributes, migrator_migrate_nla, etc. - not step1/step2. The "step6" references are in migrator.py as debug print messages, not operator names. +4. Apply naming convention: CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys - these seem to be the desired bl_label style (short, descriptive) or perhaps the user wants bl_description to reference these "true names" + +Let me read more of operators.py to see all operators, which have bl_description, and how the UI draws them. I'll also check panels.py to see which operators are drawn. +
+ +--- + + +Checking which operators the UI draws and which have `bl_description`; inspecting the migrator operators and panel layout. + + +--- + + +
Tool use: **read_file_v2** • Read file: T:\Dynamic-Link-Manager\ui\operators.py + +
+
+ +--- + + +
Tool use: **read_file_v2** • Read file: T:\Dynamic-Link-Manager\ui\panels.py + +
+
+ +--- + + +
+Tool use: **ripgrep_raw_search** + + +Parameters: + +```json +{ + "pattern": "bl_description|operators\\.|layout\\.operator", + "path": "T:\\Dynamic-Link-Manager\\ui", + "caseInsensitive": false +} +``` +Additional data: + +```json +{ + "isPruned": true, + "pattern": "bl_description|operators\\.|layout\\.operator", + "path": "T:\\Dynamic-Link-Manager\\ui", + "outputMode": "content", + "totalFiles": 2, + "totalMatches": 2, + "topFiles": [ + { + "uri": "ui/panels.py", + "matchCount": 1 + }, + { + "uri": "ui\\panels.py", + "matchCount": 1 + } + ] +} +``` +Status: **completed** + + +
+
+ +--- + +
Thought Process + +The grep for bl_description in ui didn't find any - so it seems no operators currently have bl_description. Let me double-check and also get the full list of operators drawn in the UI from panels.py. I have: + +From panels.py, operators drawn in UI: +- dlm.make_paths_relative +- dlm.make_paths_absolute +- dlm.picker_original_character +- dlm.picker_replacement_character +- dlm.run_character_migration +- dlm.migrator_copy_attributes +- dlm.migrator_migrate_nla +- dlm.migrator_custom_properties +- dlm.migrator_bone_constraints +- dlm.migrator_retarget_relations +- dlm.migrator_basebody_shapekeys +- dlm.tweak_add_arm, dlm.tweak_remove_arm, dlm.tweak_bake_arm +- dlm.tweak_add_leg, dlm.tweak_remove_leg, dlm.tweak_bake_leg +- dlm.tweak_add_both, dlm.tweak_remove_both, dlm.tweak_bake_both +- dlm.scan_linked_assets +- dlm.reload_libraries +- dlm.browse_search_path +- dlm.remove_search_path +- dlm.add_search_path +- dlm.find_libraries_in_folders +- dlm.open_linked_file +- dlm.relocate_single_library + +So the user wants: +1. Add bl_description to all operators that are drawn in the UI and don't have one (appears to be all of them - none have bl_description). +2. No operators named step1, step2 - the current operator bl_idnames are already descriptive (migrator_copy_attributes, etc.). The user said "They should all follow a naming convention along the lines of the true names: CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys." So they might want: + - Either bl_label to use these short names (CopyAttr, MigNLA, ...) + - Or bl_description to reference these "true names" + - Or both + +Re-reading: "No operators should be named step1 step2, etc. They should all follow a naming convention along the lines of the true names of the operators: CopyAttr, MigNLA, ..." + +So: (1) no step1/step2 - the codebase already uses descriptive names like migrator_copy_attributes, not step1. (2) "follow a naming convention along the lines of" those true names - so the convention is short, CamelCase or similar: CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys. + +In Blender, bl_idname must be lowercase with dots/underscores (e.g. dlm.migrator_copy_attributes). So the "naming convention" likely applies to bl_label (what users see) and/or bl_description. Currently we have bl_label like "Copy attributes", "Migrate NLA", "Custom properties", "Bone constraints", "Retarget relations", "Migrate BaseBody shapekeys" - which are already descriptive. The user's "true names" are shorter: CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys. So perhaps: +- Option A: Change bl_label to the short form (CopyAttr, MigNLA, etc.) so button text matches. +- Option B: Keep bl_label as is for clarity, add bl_description that explains what the step does and maybe mention the short name. +- Option C: Use short names in bl_description as the "operator name" and keep bl_label human-readable. + +I'll assume: (1) Add bl_description to every UI-drawn operator that doesn't have one. (2) Where operators are the migration steps, align naming with the true names - either use them as bl_label (making buttons show "CopyAttr", "MigNLA", etc.) or keep current bl_label and add bl_description that mentions the step. I'll check the panel again: buttons say "Copy attributes", "NLA", "Custom properties", etc. So the panel uses custom text in some places (e.g. text="NLA"). The user said "no operators should be named step1 step2" and "they should all follow a naming convention... CopyAttr, MigNLA...". So I'll plan: add bl_description everywhere; for the six migrator step operators, set bl_label to the canonical short names (CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys) and update panel button text to match if needed. I'll list all operators in operators.py to ensure I don't miss any. +
+ +--- + + +Checking the full operator list and whether any use "step" in their id/label: + + +--- + + +
+Tool use: **ripgrep_raw_search** + + +Parameters: + +```json +{ + "pattern": "^class DLM_OT_|bl_label|bl_description", + "path": "T:\\Dynamic-Link-Manager\\ui\\operators.py", + "caseInsensitive": false +} +``` +Additional data: + +```json +{ + "isPruned": true, + "pattern": "^class DLM_OT_|bl_label|bl_description", + "path": "T:\\Dynamic-Link-Manager\\ui\\operators.py", + "outputMode": "content", + "totalFiles": 1, + "totalMatches": 60, + "topFiles": [ + { + "uri": "ui\\operators.py", + "matchCount": 60 + } + ] +} +``` +Status: **completed** + + +
+
+ +--- + + +
Tool use: **read_file_v2** • Read file: T:\Dynamic-Link-Manager\ui\operators.py + +
+
+ +--- + +
Thought Process + +Findings: +1. **No operator has `bl_description`** in the codebase - so every UI-drawn operator needs documentation added. +2. **No operators are literally named step1/step2** - the bl_idnames are already descriptive (e.g. `dlm.migrator_copy_attributes`). The user wants the *labels* (and possibly docs) to follow the "true names": CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys. +3. **Operators drawn in the UI** (from panels.py): + - Path: make_paths_relative, make_paths_absolute + - CharMig: picker_original_character, picker_replacement_character, run_character_migration, migrator_copy_attributes, migrator_migrate_nla, migrator_custom_properties, migrator_bone_constraints, migrator_retarget_relations, migrator_basebody_shapekeys + - Tweak: tweak_add_arm, tweak_remove_arm, tweak_bake_arm, tweak_add_leg, tweak_remove_leg, tweak_bake_leg, tweak_add_both, tweak_remove_both, tweak_bake_both + - Linked libs: scan_linked_assets, reload_libraries, browse_search_path, remove_search_path, add_search_path, find_libraries_in_folders, open_linked_file, relocate_single_library + +4. **Replace linked asset** - not drawn in panels.py I saw; might be used elsewhere. I'll include all operators that could appear in UI (any operator in operators.py that is registered). + +Plan: +- Add `bl_description` to every operator in [ui/operators.py](ui/operators.py) that is drawn in the UI (and optionally all DLM operators for consistency). +- For the six migrator step operators, set `bl_label` to the canonical short names: CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys. Then update [ui/panels.py](ui/panels.py) where the panel overrides button text (e.g. "Copy attributes", "NLA", "Custom properties") to use the same short names so the UI is consistent. + +Actually re-reading the user message again: "No operators should be named step1 step2, etc. They should all follow a naming convention along the lines of the true names". So they're saying (1) don't use step1/step2 (we don't), and (2) do use the convention like CopyAttr, MigNLA, etc. So the six migration step operators should have bl_label (and panel button text) aligned to: CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys. The rest of the operators (path, picker, run migration, tweaks, library ops) just need bl_description; their names are already fine. + +Creating the plan. +
+ +--- + + +Checking for other UI references to these operators (menus, keymaps): + + +--- + + +
+Tool use: **ripgrep_raw_search** + + +Parameters: + +```json +{ + "pattern": "dlm\\.(migrator_|tweak_|run_|picker_|make_paths|scan_|reload_|browse_|remove_search|add_search|find_libraries|open_linked|relocate)", + "path": "T:\\Dynamic-Link-Manager", + "glob": "*.py", + "caseInsensitive": false +} +``` +Additional data: + +```json +{ + "isPruned": true, + "pattern": "dlm\\.(migrator_|tweak_|run_|picker_|make_paths|scan_|reload_|browse_|remove_search|add_search|find_libraries|open_linked|relocate)", + "path": "T:\\Dynamic-Link-Manager", + "outputMode": "content", + "totalFiles": 6, + "totalMatches": 140, + "topFiles": [ + { + "uri": "ui/operators.py", + "matchCount": 40 + }, + { + "uri": "ui\\panels.py", + "matchCount": 28 + }, + { + "uri": "ui\\operators.py", + "matchCount": 40 + }, + { + "uri": "ui/preferences.py", + "matchCount": 3 + }, + { + "uri": "ops/library.py", + "matchCount": 1 + }, + { + "uri": "ui/panels.py", + "matchCount": 28 + } + ] +} +``` +Status: **completed** + + +
+
+ +--- + +
Thought Process + +I have a complete picture. No operators use step1/step2 in bl_idname or bl_label. The six migrator operators need: +1. bl_label updated to: CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys +2. bl_description added for each + +Panel button text in panels.py currently overrides for the six steps - we should update those to match the new bl_label (CopyAttr, MigNLA, etc.) so tooltips and search show the same names. + +I'll create the plan now. +
+ +--- + + +Creating the plan. + + +--- + + +
+Tool use: **create_plan** + + +Parameters: + +```json +{ + "plan": "# Operator documentation and naming convention\n\n## Current state\n\n- **No operator has `bl_description`** in [ui/operators.py](ui/operators.py). Blender uses this for tooltips and search.\n- **No operators use step1/step2** — `bl_idname`s are already descriptive (e.g. `dlm.migrator_copy_attributes`). The only \"step\" references are debug `print` strings in [ops/migrator.py](ops/migrator.py) (e.g. `[DLM step6]`); those are out of scope unless you want them renamed for consistency.\n- **Six migrator step operators** currently have `bl_label` like \"Copy attributes\", \"Migrate NLA\", \"Custom properties\", \"Bone constraints\", \"Retarget relations\", \"Migrate BaseBody shapekeys\". You want these to use the canonical short names: **CopyAttr**, **MigNLA**, **MigCustProps**, **MigBoneConst**, **RetargRelatives**, **MigBBodyShapeKeys**.\n- **Panel button text** in [ui/panels.py](ui/panels.py) overrides labels for the six steps (e.g. `text=\"NLA\"`, `text=\"Copy attributes\"`). These should be updated to match the new `bl_label` so the UI and search/tooltips are consistent.\n\n## Scope: operators drawn in the UI\n\nFrom [ui/panels.py](ui/panels.py) and [ui/preferences.py](ui/preferences.py):\n\n| Area | Operators |\n|------|-----------|\n| Path | `make_paths_relative`, `make_paths_absolute` |\n| CharMig | `picker_original_character`, `picker_replacement_character`, `run_character_migration`, and the six step ops |\n| Tweak Tools | `tweak_add_arm`, `tweak_remove_arm`, `tweak_bake_arm`, `tweak_add_leg`, `tweak_remove_leg`, `tweak_bake_leg`, `tweak_add_both`, `tweak_remove_both`, `tweak_bake_both` |\n| Linked Libraries | `scan_linked_assets`, `reload_libraries`, `browse_search_path`, `remove_search_path`, `add_search_path`, `find_libraries_in_folders`, `open_linked_file`, `relocate_single_library` |\n\nOptionally include `replace_linked_asset` and `attempt_relink` if they appear in menus; they are registered but not drawn in the main panel.\n\n---\n\n## 1. Add `bl_description` to all UI-drawn operators ([ui/operators.py](ui/operators.py))\n\nAdd a single line after `bl_label` (and after `bl_icon` where present) for each operator, e.g.:\n\n- **Replace Linked Asset** — e.g. \"Open file browser to replace the linked asset with another file.\"\n- **Scan Linked Libraries** — e.g. \"Scan the current file for linked libraries and list their status.\"\n- **Find Libraries in Folders** — e.g. \"Search addon search paths for missing library blend files.\"\n- **Open Linked File** — e.g. \"Open the selected linked blend file in a new Blender instance.\"\n- **Add / Remove / Browse Search Path** — one-line descriptions for path list management.\n- **Attempt Relink** — e.g. \"Try to relink missing libraries using the configured search paths.\"\n- **Reload Libraries** — e.g. \"Reload all linked libraries (or fallback manual reload).\"\n- **Make Paths Relative / Absolute** — e.g. \"Convert all internal file paths to relative (or absolute).\"\n- **Relocate Library** — e.g. \"Point a selected library to a new blend file and reload.\"\n- **Six migrator steps** — short descriptions of what each step does (copy object/armature attributes; migrate NLA; copy custom properties; migrate bone constraints; retarget relations; migrate base body shape keys). Can reference the short name in the description if desired.\n- **Run Character Migration** — e.g. \"Run all six migration steps (CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys) in order.\"\n- **Pick Original / Pick Replacement** — e.g. \"Set the original (or replacement) character armature from the active object.\"\n- **Tweak operators (Add/Remove/Bake × Arm/Leg/Both)** — one-line descriptions for adding/removing/baking tweak constraints.\n\nKeep each description one short sentence so tooltips stay readable.\n\n---\n\n## 2. Rename six migrator step operators to canonical names ([ui/operators.py](ui/operators.py))\n\nUpdate only the six step operators:\n\n| Current `bl_label` | New `bl_label` |\n|--------------------|----------------|\n| Copy attributes | **CopyAttr** |\n| Migrate NLA | **MigNLA** |\n| Custom properties | **MigCustProps** |\n| Bone constraints | **MigBoneConst** |\n| Retarget relations | **RetargRelatives** |\n| Migrate BaseBody shapekeys | **MigBBodyShapeKeys** |\n\nDo **not** change `bl_idname` (e.g. `dlm.migrator_copy_attributes`) to avoid breaking keymaps or saved files; only `bl_label` and panel button text.\n\n---\n\n## 3. Update panel button text ([ui/panels.py](ui/panels.py))\n\nIn the Character Migrator box, the layout currently uses custom `text=` for the six step buttons. Update them to match the new `bl_label` so tooltip and button text align:\n\n- `text=\"Copy attributes\"` → `text=\"CopyAttr\"`\n- `text=\"NLA\"` → `text=\"MigNLA\"`\n- `text=\"Custom properties\"` → `text=\"MigCustProps\"`\n- `text=\"Bone constraints\"` → `text=\"MigBoneConst\"`\n- `text=\"Retarget relations\"` → `text=\"RetargRelatives\"`\n- `text=\"BaseBody ShapeKeys\"` → `text=\"MigBBodyShapeKeys\"`\n\nYou can omit the `text=` argument to use `bl_label` by default, which would keep a single source of truth in operators.py.\n\n---\n\n## 4. Optional: debug prints in migrator\n\n[ops/migrator.py](ops/migrator.py) uses `[DLM step6]` in print statements. Renaming these to e.g. `[DLM MigBBodyShapeKeys]` is optional and would make logs consistent with the operator names; include only if you want log alignment.\n\n---\n\n## Summary of edits\n\n- **[ui/operators.py](ui/operators.py):** Add `bl_description` to every operator that is drawn in the UI (and optionally to `replace_linked_asset` / `attempt_relink`). Change `bl_label` of the six migrator step classes to CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys.\n- **[ui/panels.py](ui/panels.py):** Update the six `layout.operator(..., text=\"...\")` calls in the Character Migrator section to use the new labels (either explicit `text=\"CopyAttr\"` etc. or remove `text` to use `bl_label`).\n\nNo changes to `bl_idname`, registration, or [ops/migrator.py](ops/migrator.py) logic; only documentation and display names.\n", + "name": "Operator docs and naming", + "overview": "Add bl_description to every operator drawn in the UI and align the six character-migrator step operators to the canonical short names (CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys). No operators are currently named step1/step2; only labels and docs need updating." +} +``` +Additional data: + +```json +{ + "reviewData": { + "status": "Requested", + "selectedOption": "none", + "isShowingInput": false + }, + "planUri": "file:///c%3A/Users/Nathan/.cursor/plans/operator_docs_and_naming_8f8ed6b9.plan.md", + "hasOpenedEditor": true +} +``` +Result: + +```json +{ + "rejected": {} +} +``` +Status: **completed** + + +
+
+ +--- + +_**User**_ + +Implement the plan as specified, it is attached for your reference. Do NOT edit the plan file itself. + +To-do's from the plan have already been created. Do not create them again. Mark them as in_progress as you work, starting with the first one. Don't stop until you have completed all the to-dos. + +--- + +_**Agent (model default, mode Agent)**_ + +
Thought Process + +The user wants me to implement the plan for operator documentation and naming. Let me check the todos first and then implement: + +1. Add `bl_description` to all UI-drawn operators in ui/operators.py +2. Rename six migrator step operators to canonical names (bl_label) in ui/operators.py +3. Update panel button text in ui/panels.py + +I'll need to read the current todos, then make the edits. Let me start by reading the operators file fully to add all bl_descriptions and update the six bl_labels, then update panels.py. +
+ +--- + + + + + +--- + + +
Tool use: **todo_write** • Todo List + +- [-] Add bl_description to all UI-drawn operators (ui/operators.py) +- [ ] Rename six migrator step bl_labels to canonical names +- [ ] Update panel button text for six steps (ui/panels.py) +- [x] Add 9 tweak operators and register in operators.py + +
+
+ +--- + + +
Tool use: **read_file_v2** • Read file: T:\Dynamic-Link-Manager\ui\operators.py + +
+
+ +--- + +
Thought Process + +I'll add bl_description to every operator and update the six migrator step bl_labels in one pass through operators.py. I'll do multiple search_replace calls. +
+ +--- + + +Adding `bl_description` to all operators and updating the six migrator `bl_label`s. + + +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + +
Thought Process + +Good progress. Now add bl_description and update bl_label for the six migrator steps, then run_character_migration, pickers, and tweak operators. +
+ +--- + + + + + +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\operators.py + +
+ +
+ +--- + +
Thought Process + +All operators now have bl_description and the six migrator steps have the new bl_labels. Updating the error message in run_character_migration to use the new step names for consistency (it says "Migration failed at step {i + 1}: {MIGRATOR_STEP_OPS[i]}"). The plan didn't ask to change that - MIGRATOR_STEP_OPS holds bl_idnames. The report could say the step name for clarity; I'll leave it as is unless we want to show the bl_label. Actually the plan said no logic changes. So leave it. + +Now mark todo 1 and 2 complete and do todo 3: update panel button text in panels.py. +
+ +--- + + + + + +--- + + +
Tool use: **todo_write** • Todo List + +- [x] Add bl_description to all UI-drawn operators (ui/operators.py) +- [x] Rename six migrator step bl_labels to canonical names +- [-] Update panel button text for six steps (ui/panels.py) +- [x] Add 9 tweak operators and register in operators.py + +
+
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ui\panels.py + +
+ +
+ +--- + +
Thought Process + +Panel is updated. Mark todo 3 complete and run lints on the edited files. +
+ +--- + + + + + +--- + + +
Tool use: **todo_write** • Todo List + +- [x] Add bl_description to all UI-drawn operators (ui/operators.py) +- [x] Rename six migrator step bl_labels to canonical names +- [x] Update panel button text for six steps (ui/panels.py) +- [x] Add 9 tweak operators and register in operators.py + +
+
+ +--- + + +
+Tool use: **read_lints** + + +Parameters: + +```json +{ + "paths": [ + "T:\\Dynamic-Link-Manager\\ui\\operators.py", + "T:\\Dynamic-Link-Manager\\ui\\panels.py" + ] +} +``` +Result: + +```json +{ + "linterErrorsByFile": [ + { + "relativeWorkspacePath": "T:\\Dynamic-Link-Manager\\ui\\operators.py" + }, + { + "relativeWorkspacePath": "T:\\Dynamic-Link-Manager\\ui\\panels.py" + } + ] +} +``` +Status: **completed** + + +
+
+ +--- + +
Thought Process + +All tasks are done. No linter errors. I'll give a short summary to the user. +
+ +--- + + +Summary of what was implemented: + +**1. [ui/operators.py](ui/operators.py)** +- **bl_description** added for every operator (all 27), including: + - Library/path: replace_linked_asset, scan_linked_assets, find_libraries_in_folders, open_linked_file, add/remove/browse_search_path, attempt_relink, reload_libraries, make_paths_relative/absolute, relocate_single_library + - Character migrator: run_character_migration, picker_original_character, picker_replacement_character, and the six step operators + - Tweak tools: all nine add/remove/bake (arm/leg/both) operators + +- **Six migrator step bl_labels** set to the canonical short names: + - Copy attributes → **CopyAttr** + - Migrate NLA → **MigNLA** + - Custom properties → **MigCustProps** + - Bone constraints → **MigBoneConst** + - Retarget relations → **RetargRelatives** + - Migrate BaseBody shapekeys → **MigBBodyShapeKeys** + +**2. [ui/panels.py](ui/panels.py)** +- The six step buttons in the Character Migrator box now use the same labels: `CopyAttr`, `MigNLA`, `MigCustProps`, `MigBoneConst`, `RetargRelatives`, `MigBBodyShapeKeys`. + +`bl_idname` values were not changed. Linting reports no issues. + +--- + +_**User**_ + +Sorry, I was referring to "run_step_x" defs in migrator.py. + +--- + +_**Agent (model default, mode Agent)**_ + + --- diff --git a/ops/migrator.py b/ops/migrator.py index f20bae0..7551baa 100644 --- a/ops/migrator.py +++ b/ops/migrator.py @@ -37,8 +37,8 @@ def get_pair_automatic(context): return pairs[0] if pairs else (None, None) -def run_step_1(orig, rep): - """Copy armature object attributes: location, rotation, scale.""" +def run_copy_attr(orig, rep): + """Copy armature object attributes: location, rotation, scale (CopyAttr).""" rep.location = orig.location.copy() if orig.rotation_mode == "QUATERNION": rep.rotation_quaternion = orig.rotation_quaternion.copy() @@ -64,8 +64,8 @@ def _mirror_als_turn_on(orig, rep): pass -def run_step_2(orig, rep): - """Migrate NLA: copy tracks and strips to replacement; or apply active action only.""" +def run_mig_nla(orig, rep): + """Migrate NLA: copy tracks and strips to replacement; or apply active action only (MigNLA).""" if not orig.animation_data: return ad = orig.animation_data @@ -127,7 +127,7 @@ def run_step_2(orig, rep): EXCLUDE_PROPS = {"_RNA_UI", "rigify_type", "rigify_parameters"} -def run_step_3(orig, rep): +def run_mig_cust_props(orig, rep): """Custom properties: copy pose-bone custom props, exclude rigify internals.""" for pbone in orig.pose.bones: if pbone.name not in rep.pose.bones: @@ -142,7 +142,7 @@ def run_step_3(orig, rep): pass -def run_step_4(orig, rep, orig_to_rep): +def run_mig_bone_const(orig, rep, orig_to_rep): """Bone constraints: remove stale on rep, copy from orig with retarget, trim duplicates.""" other_originals = [o for o in orig_to_rep if o != orig] for pb in rep.pose.bones: @@ -181,7 +181,7 @@ def run_step_4(orig, rep, orig_to_rep): rr.remove(rr[-1]) -def run_step_5(orig, rep, rep_descendants, orig_to_rep): +def run_retarg_relatives(orig, rep, rep_descendants, orig_to_rep): """Retarget relations: parents, constraint targets, Armature modifiers to rep.""" candidates = set(rep_descendants) for ob in bpy.data.objects: @@ -255,7 +255,7 @@ def _find_base_body(armature, descendants_iter, rep_base_name=None): return candidates[0] -def run_step_6(orig, rep, rep_descendants, context=None): +def run_mig_bbody_shapekeys(orig, rep, rep_descendants, context=None): """Replacement base body: library override (fully editable when context given), copy shapekey values, then shape-key action.""" orig_descendants = list(descendants(orig)) for ob in list(rep_descendants): @@ -366,12 +366,12 @@ def run_full_migration(context): rep_descendants = descendants(rep) try: - run_step_1(orig, rep) - run_step_2(orig, rep) - run_step_3(orig, rep) - run_step_4(orig, rep, orig_to_rep) - run_step_5(orig, rep, rep_descendants, orig_to_rep) - run_step_6(orig, rep, rep_descendants, context) + run_copy_attr(orig, rep) + run_mig_nla(orig, rep) + run_mig_cust_props(orig, rep) + run_mig_bone_const(orig, rep, orig_to_rep) + run_retarg_relatives(orig, rep, rep_descendants, orig_to_rep) + run_mig_bbody_shapekeys(orig, rep, rep_descendants, context) except Exception as e: return False, str(e) return True, f"Migrated {orig.name} → {rep.name}" diff --git a/ui/operators.py b/ui/operators.py index bd6b4ae..720cb36 100644 --- a/ui/operators.py +++ b/ui/operators.py @@ -18,6 +18,7 @@ def _prefs(context): class DLM_OT_replace_linked_asset(Operator): bl_idname = "dlm.replace_linked_asset" bl_label = "Replace Linked Asset" + bl_description = "Open file browser to replace the linked asset with another file" bl_options = {"REGISTER", "UNDO"} filepath: StringProperty(name="File Path", description="Path to the new asset file", subtype="FILE_PATH") @@ -48,6 +49,7 @@ class DLM_OT_replace_linked_asset(Operator): class DLM_OT_scan_linked_assets(Operator): bl_idname = "dlm.scan_linked_assets" bl_label = "Scan Linked Libraries" + bl_description = "Scan the current file for linked libraries and list their status" bl_options = {"REGISTER"} def execute(self, context): @@ -59,6 +61,7 @@ class DLM_OT_scan_linked_assets(Operator): class DLM_OT_find_libraries_in_folders(Operator): bl_idname = "dlm.find_libraries_in_folders" bl_label = "Find Libraries in Folders" + bl_description = "Search addon search paths for missing library blend files" bl_options = {"REGISTER", "UNDO"} def execute(self, context): @@ -70,6 +73,7 @@ class DLM_OT_find_libraries_in_folders(Operator): class DLM_OT_open_linked_file(Operator): bl_idname = "dlm.open_linked_file" bl_label = "Open Linked File" + bl_description = "Open the selected linked blend file in a new Blender instance" bl_options = {"REGISTER"} filepath: StringProperty(name="File Path", default="") @@ -89,6 +93,7 @@ class DLM_OT_open_linked_file(Operator): class DLM_OT_add_search_path(Operator): bl_idname = "dlm.add_search_path" bl_label = "Add Search Path" + bl_description = "Add a new folder to the list of search paths for finding libraries" bl_options = {"REGISTER"} def execute(self, context): @@ -103,6 +108,7 @@ class DLM_OT_add_search_path(Operator): class DLM_OT_remove_search_path(Operator): bl_idname = "dlm.remove_search_path" bl_label = "Remove Search Path" + bl_description = "Remove the selected search path from the list" bl_options = {"REGISTER"} index: IntProperty(name="Index", default=0) @@ -117,6 +123,7 @@ class DLM_OT_remove_search_path(Operator): class DLM_OT_attempt_relink(Operator): bl_idname = "dlm.attempt_relink" bl_label = "Attempt Relink" + bl_description = "Try to relink missing libraries using the configured search paths" bl_options = {"REGISTER"} def execute(self, context): @@ -128,6 +135,7 @@ class DLM_OT_attempt_relink(Operator): class DLM_OT_browse_search_path(Operator): bl_idname = "dlm.browse_search_path" bl_label = "Browse Search Path" + bl_description = "Browse to set the folder for the selected search path" bl_options = {"REGISTER"} index: IntProperty(name="Index", default=0) filepath: StringProperty(name="Search Path", subtype="DIR_PATH") @@ -150,6 +158,7 @@ class DLM_OT_browse_search_path(Operator): class DLM_OT_reload_libraries(Operator): bl_idname = "dlm.reload_libraries" bl_label = "Reload Libraries" + bl_description = "Reload all linked libraries (or fallback manual reload)" bl_options = {"REGISTER"} def execute(self, context): @@ -171,6 +180,7 @@ class DLM_OT_reload_libraries(Operator): class DLM_OT_make_paths_relative(Operator): bl_idname = "dlm.make_paths_relative" bl_label = "Make Paths Relative" + bl_description = "Convert all internal file paths to relative" bl_options = {"REGISTER"} def execute(self, context): @@ -186,6 +196,7 @@ class DLM_OT_make_paths_relative(Operator): class DLM_OT_make_paths_absolute(Operator): bl_idname = "dlm.make_paths_absolute" bl_label = "Make Paths Absolute" + bl_description = "Convert all internal file paths to absolute" bl_options = {"REGISTER"} def execute(self, context): @@ -201,6 +212,7 @@ class DLM_OT_make_paths_absolute(Operator): class DLM_OT_relocate_single_library(Operator): bl_idname = "dlm.relocate_single_library" bl_label = "Relocate Library" + bl_description = "Point the selected library to a new blend file and reload" bl_options = {"REGISTER", "UNDO"} target_filepath: StringProperty(name="Current Library Path", default="") filepath: StringProperty(name="New Library File", subtype="FILE_PATH", default="") @@ -256,7 +268,8 @@ def _get_migrator_pair(context): class DLM_OT_migrator_copy_attributes(Operator): bl_idname = "dlm.migrator_copy_attributes" - bl_label = "Copy attributes" + bl_label = "CopyAttr" + bl_description = "Copy object and armature attributes from original to replacement character" bl_icon = "COPY_ID" bl_options = {"REGISTER", "UNDO"} @@ -266,8 +279,8 @@ class DLM_OT_migrator_copy_attributes(Operator): self.report({"ERROR"}, "No valid character pair (set Original/Replacement or enable Automatic).") return {"CANCELLED"} try: - from ..ops.migrator import run_step_1 - run_step_1(orig, rep) + from ..ops.migrator import run_copy_attr + run_copy_attr(orig, rep) self.report({"INFO"}, "Copy attributes done.") return {"FINISHED"} except Exception as e: @@ -277,7 +290,8 @@ class DLM_OT_migrator_copy_attributes(Operator): class DLM_OT_migrator_migrate_nla(Operator): bl_idname = "dlm.migrator_migrate_nla" - bl_label = "Migrate NLA" + bl_label = "MigNLA" + bl_description = "Migrate NLA tracks and strips from original to replacement character" bl_icon = "NLA" bl_options = {"REGISTER", "UNDO"} @@ -287,8 +301,8 @@ class DLM_OT_migrator_migrate_nla(Operator): self.report({"ERROR"}, "No valid character pair.") return {"CANCELLED"} try: - from ..ops.migrator import run_step_2 - run_step_2(orig, rep) + from ..ops.migrator import run_mig_nla + run_mig_nla(orig, rep) self.report({"INFO"}, "Migrate NLA done.") return {"FINISHED"} except Exception as e: @@ -298,7 +312,8 @@ class DLM_OT_migrator_migrate_nla(Operator): class DLM_OT_migrator_custom_properties(Operator): bl_idname = "dlm.migrator_custom_properties" - bl_label = "Custom properties" + bl_label = "MigCustProps" + bl_description = "Copy custom properties from original to replacement character" bl_icon = "PROPERTIES" bl_options = {"REGISTER", "UNDO"} @@ -308,8 +323,8 @@ class DLM_OT_migrator_custom_properties(Operator): self.report({"ERROR"}, "No valid character pair.") return {"CANCELLED"} try: - from ..ops.migrator import run_step_3 - run_step_3(orig, rep) + from ..ops.migrator import run_mig_cust_props + run_mig_cust_props(orig, rep) self.report({"INFO"}, "Custom properties done.") return {"FINISHED"} except Exception as e: @@ -319,7 +334,8 @@ class DLM_OT_migrator_custom_properties(Operator): class DLM_OT_migrator_bone_constraints(Operator): bl_idname = "dlm.migrator_bone_constraints" - bl_label = "Bone constraints" + bl_label = "MigBoneConst" + bl_description = "Migrate bone constraints from original to replacement armature" bl_icon = "CONSTRAINT_BONE" bl_options = {"REGISTER", "UNDO"} @@ -329,9 +345,9 @@ class DLM_OT_migrator_bone_constraints(Operator): self.report({"ERROR"}, "No valid character pair.") return {"CANCELLED"} try: - from ..ops.migrator import run_step_4 + from ..ops.migrator import run_mig_bone_const orig_to_rep = {orig: rep} - run_step_4(orig, rep, orig_to_rep) + run_mig_bone_const(orig, rep, orig_to_rep) self.report({"INFO"}, "Bone constraints done.") return {"FINISHED"} except Exception as e: @@ -341,7 +357,8 @@ class DLM_OT_migrator_bone_constraints(Operator): class DLM_OT_migrator_retarget_relations(Operator): bl_idname = "dlm.migrator_retarget_relations" - bl_label = "Retarget relations" + bl_label = "RetargRelatives" + bl_description = "Retarget parent/child and other relations to the replacement character" bl_icon = "ORIENTATION_PARENT" bl_options = {"REGISTER", "UNDO"} @@ -351,11 +368,11 @@ class DLM_OT_migrator_retarget_relations(Operator): self.report({"ERROR"}, "No valid character pair.") return {"CANCELLED"} try: - from ..ops.migrator import run_step_5 + from ..ops.migrator import run_retarg_relatives from ..utils import descendants rep_descendants = descendants(rep) orig_to_rep = {orig: rep} - run_step_5(orig, rep, rep_descendants, orig_to_rep) + run_retarg_relatives(orig, rep, rep_descendants, orig_to_rep) self.report({"INFO"}, "Retarget relations done.") return {"FINISHED"} except Exception as e: @@ -365,7 +382,8 @@ class DLM_OT_migrator_retarget_relations(Operator): class DLM_OT_migrator_basebody_shapekeys(Operator): bl_idname = "dlm.migrator_basebody_shapekeys" - bl_label = "Migrate BaseBody shapekeys" + bl_label = "MigBBodyShapeKeys" + bl_description = "Migrate base body mesh shape key values from original to replacement" bl_icon = "SHAPEKEY_DATA" bl_options = {"REGISTER", "UNDO"} @@ -375,10 +393,10 @@ class DLM_OT_migrator_basebody_shapekeys(Operator): self.report({"ERROR"}, "No valid character pair.") return {"CANCELLED"} try: - from ..ops.migrator import run_step_6 + from ..ops.migrator import run_mig_bbody_shapekeys from ..utils import descendants rep_descendants = descendants(rep) - run_step_6(orig, rep, rep_descendants, context) + run_mig_bbody_shapekeys(orig, rep, rep_descendants, context) self.report({"INFO"}, "Migrate BaseBody shapekeys done.") return {"FINISHED"} except Exception as e: @@ -399,6 +417,7 @@ MIGRATOR_STEP_OPS = ( class DLM_OT_run_character_migration(Operator): bl_idname = "dlm.run_character_migration" bl_label = "Run Character Migration" + bl_description = "Run all six migration steps (CopyAttr, MigNLA, MigCustProps, MigBoneConst, RetargRelatives, MigBBodyShapeKeys) in order" bl_options = {"REGISTER", "UNDO"} def execute(self, context): @@ -422,6 +441,7 @@ class DLM_OT_run_character_migration(Operator): class DLM_OT_picker_original_character(Operator): bl_idname = "dlm.picker_original_character" bl_label = "Pick Original" + bl_description = "Set the original character armature from the active object" bl_options = {"REGISTER"} def execute(self, context): @@ -437,6 +457,7 @@ class DLM_OT_picker_original_character(Operator): class DLM_OT_picker_replacement_character(Operator): bl_idname = "dlm.picker_replacement_character" bl_label = "Pick Replacement" + bl_description = "Set the replacement character armature from the active object" bl_options = {"REGISTER"} def execute(self, context): @@ -457,6 +478,7 @@ def _tweak_poll(context): class DLM_OT_tweak_add_arm(Operator): bl_idname = "dlm.tweak_add_arm" bl_label = "Add Arm Tweaks" + bl_description = "Add tweak bone constraints to arm bones on the replacement character" bl_options = {"REGISTER", "UNDO"} @classmethod @@ -474,6 +496,7 @@ class DLM_OT_tweak_add_arm(Operator): class DLM_OT_tweak_remove_arm(Operator): bl_idname = "dlm.tweak_remove_arm" bl_label = "Remove Arm Tweaks" + bl_description = "Remove arm tweak constraints from the replacement character" bl_options = {"REGISTER", "UNDO"} @classmethod @@ -491,6 +514,7 @@ class DLM_OT_tweak_remove_arm(Operator): class DLM_OT_tweak_bake_arm(Operator): bl_idname = "dlm.tweak_bake_arm" bl_label = "Bake Arm Tweaks" + bl_description = "Bake arm tweak constraints to keyframes and optionally remove constraints" bl_options = {"REGISTER", "UNDO"} @classmethod @@ -516,6 +540,7 @@ class DLM_OT_tweak_bake_arm(Operator): class DLM_OT_tweak_add_leg(Operator): bl_idname = "dlm.tweak_add_leg" bl_label = "Add Leg Tweaks" + bl_description = "Add tweak bone constraints to leg bones on the replacement character" bl_options = {"REGISTER", "UNDO"} @classmethod @@ -533,6 +558,7 @@ class DLM_OT_tweak_add_leg(Operator): class DLM_OT_tweak_remove_leg(Operator): bl_idname = "dlm.tweak_remove_leg" bl_label = "Remove Leg Tweaks" + bl_description = "Remove leg tweak constraints from the replacement character" bl_options = {"REGISTER", "UNDO"} @classmethod @@ -550,6 +576,7 @@ class DLM_OT_tweak_remove_leg(Operator): class DLM_OT_tweak_bake_leg(Operator): bl_idname = "dlm.tweak_bake_leg" bl_label = "Bake Leg Tweaks" + bl_description = "Bake leg tweak constraints to keyframes and optionally remove constraints" bl_options = {"REGISTER", "UNDO"} @classmethod @@ -575,6 +602,7 @@ class DLM_OT_tweak_bake_leg(Operator): class DLM_OT_tweak_add_both(Operator): bl_idname = "dlm.tweak_add_both" bl_label = "Add Arm & Leg Tweaks" + bl_description = "Add tweak bone constraints to both arm and leg bones" bl_options = {"REGISTER", "UNDO"} @classmethod @@ -592,6 +620,7 @@ class DLM_OT_tweak_add_both(Operator): class DLM_OT_tweak_remove_both(Operator): bl_idname = "dlm.tweak_remove_both" bl_label = "Remove Arm & Leg Tweaks" + bl_description = "Remove all arm and leg tweak constraints from the replacement character" bl_options = {"REGISTER", "UNDO"} @classmethod @@ -609,6 +638,7 @@ class DLM_OT_tweak_remove_both(Operator): class DLM_OT_tweak_bake_both(Operator): bl_idname = "dlm.tweak_bake_both" bl_label = "Bake Arm & Leg Tweaks" + bl_description = "Bake all arm and leg tweak constraints to keyframes and optionally remove constraints" bl_options = {"REGISTER", "UNDO"} @classmethod diff --git a/ui/panels.py b/ui/panels.py index 94cf3e8..78ba48d 100644 --- a/ui/panels.py +++ b/ui/panels.py @@ -86,13 +86,13 @@ class DLM_PT_main_panel(Panel): row = box.row() row.operator("dlm.run_character_migration", text="Run migration", icon="ARMATURE_DATA") row = box.row(align=True) - row.operator("dlm.migrator_copy_attributes", text="Copy attributes", icon="COPY_ID") - row.operator("dlm.migrator_migrate_nla", text="NLA", icon="NLA") - row.operator("dlm.migrator_custom_properties", text="Custom properties", icon="PROPERTIES") + row.operator("dlm.migrator_copy_attributes", text="CopyAttr", icon="COPY_ID") + row.operator("dlm.migrator_migrate_nla", text="MigNLA", icon="NLA") + row.operator("dlm.migrator_custom_properties", text="MigCustProps", icon="PROPERTIES") row = box.row(align=True) - row.operator("dlm.migrator_bone_constraints", text="Bone constraints", icon="CONSTRAINT_BONE") - row.operator("dlm.migrator_retarget_relations", text="Retarget relations", icon="ORIENTATION_PARENT") - row.operator("dlm.migrator_basebody_shapekeys", text="BaseBody ShapeKeys", icon="SHAPEKEY_DATA") + row.operator("dlm.migrator_bone_constraints", text="MigBoneConst", icon="CONSTRAINT_BONE") + row.operator("dlm.migrator_retarget_relations", text="RetargRelatives", icon="ORIENTATION_PARENT") + row.operator("dlm.migrator_basebody_shapekeys", text="MigBBodyShapeKeys", icon="SHAPEKEY_DATA") # Tweak Tools tweak_box = layout.box()