- Request (globe) on casting rows and loaded assets whose latest publish is not on this site, and Request Missing for all of them, through the new wtdcmds command wtd_request_revisions. Requested publishes show "requested, waiting for the download". - The version picker requests a version that is not on this site. - A 404 explains that the session is gone or wtdcmds is too old. - Fake server: car (vehicles) with a publish not on this site, wtd_request_revisions and /_test/download; 45 checks. - Tested live: car_paul modeling.blend v001 -> Requested. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
580 lines
22 KiB
Python
580 lines
22 KiB
Python
import textwrap
|
|
|
|
import bpy
|
|
|
|
from .. import config, rename, shot_viewer, tools_ops
|
|
from ..scene_manager import ipc
|
|
from ..scene_manager import library as sm_library
|
|
from ..scene_manager import operators as sm
|
|
from ..core import CheckContext, Severity, checks_for_context, contexts, runner
|
|
from ..core.runner import Status
|
|
from .operators import EXPANDED
|
|
|
|
STATUS_ICONS = {
|
|
Status.NOT_RUN: "DOT",
|
|
Status.PASSED: "CHECKMARK",
|
|
Status.INFO: "INFO",
|
|
Status.WARNING: "ERROR",
|
|
Status.ERROR: "CANCEL",
|
|
Status.SKIPPED: "REMOVE",
|
|
Status.CRASHED: "GHOST_ENABLED",
|
|
}
|
|
SEVERITY_ICONS = {
|
|
Severity.INFO: "INFO",
|
|
Severity.WARNING: "ERROR",
|
|
Severity.ERROR: "CANCEL",
|
|
}
|
|
|
|
|
|
def _wrapped_label(layout, context, text, icon="NONE", margin=0):
|
|
"""Label wrapped to the region width. ``margin`` is the room (in characters) taken by buttons."""
|
|
char_width = 6.5 * context.preferences.system.ui_scale
|
|
width = max(16, int(context.region.width / char_width) - 6 - margin)
|
|
col = layout.column(align=True)
|
|
for index, line in enumerate(textwrap.wrap(text, width) or [""]):
|
|
col.label(text=line, icon=icon if index == 0 else "BLANK1")
|
|
|
|
|
|
def draw_sanity_checks_panel(self, context):
|
|
layout = self.layout
|
|
scene = context.scene
|
|
settings = scene.wtd_sanity
|
|
report = runner.LAST_REPORT
|
|
if report is not None and report.context_id != settings.context:
|
|
report = None
|
|
|
|
layout.prop(settings, "context", text="")
|
|
if settings.context in contexts.ASSET:
|
|
row = layout.row(align=True)
|
|
row.prop(settings, "asset_name", text="Asset")
|
|
if not settings.asset_name:
|
|
guessed = CheckContext(scene, settings.context).asset_name
|
|
row.label(text=guessed or "(from file name)")
|
|
|
|
row = layout.row(align=True)
|
|
row.scale_y = 1.4
|
|
row.operator("wtd_sanity.run_checks", text="Run Checks", icon="PLAY")
|
|
row.operator("wtd_sanity.fix_all", text="Fix All", icon="TOOL_SETTINGS")
|
|
row.operator("wtd_sanity.write_report", text="", icon="TEXT")
|
|
|
|
if settings.context == contexts.CHAR_MOD:
|
|
layout.operator("wtd_sanity.export_char_reference", icon="EXPORT")
|
|
|
|
if report is not None:
|
|
counts = report.counts()
|
|
row = layout.row()
|
|
for status in (
|
|
Status.PASSED,
|
|
Status.WARNING,
|
|
Status.ERROR,
|
|
Status.SKIPPED,
|
|
Status.CRASHED,
|
|
):
|
|
if counts[status]:
|
|
row.label(text=str(counts[status]), icon=STATUS_ICONS[status])
|
|
|
|
disabled = runner.disabled_check_ids(scene)
|
|
box = None
|
|
category = None
|
|
for check in checks_for_context(settings.context):
|
|
if check.category != category:
|
|
category = check.category
|
|
box = layout.box()
|
|
box.label(text=category)
|
|
_draw_check(box, context, check, report, check.id in disabled)
|
|
|
|
|
|
def _draw_check(layout, context, check, report, disabled):
|
|
result = report.results.get(check.id) if report else None
|
|
status = result.status if result else Status.NOT_RUN
|
|
expanded = check.id in EXPANDED
|
|
|
|
row = layout.row(align=True)
|
|
row.operator(
|
|
"wtd_sanity.toggle_check",
|
|
text="",
|
|
emboss=False,
|
|
icon="CHECKBOX_DEHLT" if disabled else "CHECKBOX_HLT",
|
|
).check_id = check.id
|
|
row.operator(
|
|
"wtd_sanity.toggle_expand",
|
|
text="",
|
|
emboss=False,
|
|
icon="DOWNARROW_HLT" if expanded else "RIGHTARROW",
|
|
).check_id = check.id
|
|
|
|
label_row = row.row(align=True)
|
|
label_row.enabled = not disabled
|
|
label_row.alert = status in {Status.ERROR, Status.CRASHED}
|
|
count = f" ({len(result.issues)})" if result and result.issues else ""
|
|
label_row.label(text=check.label + count, icon=STATUS_ICONS[status])
|
|
|
|
buttons = row.row(align=True)
|
|
if result and any(issue.id_name or issue.elements for issue in result.issues):
|
|
buttons.operator(
|
|
"wtd_sanity.select_issues", text="", icon="RESTRICT_SELECT_OFF"
|
|
).check_id = check.id
|
|
if result and result.failed and check.can_fix():
|
|
buttons.operator(
|
|
"wtd_sanity.fix_check", text="", icon="TOOL_SETTINGS"
|
|
).check_id = check.id
|
|
buttons.operator(
|
|
"wtd_sanity.run_checks", text="", icon="FILE_REFRESH"
|
|
).check_id = check.id
|
|
|
|
if not expanded:
|
|
return
|
|
col = layout.column()
|
|
col.separator(factor=0.3)
|
|
_wrapped_label(col, context, check.description, icon="QUESTION")
|
|
if result is None:
|
|
return
|
|
if result.message:
|
|
_wrapped_label(
|
|
col,
|
|
context,
|
|
result.message.strip().splitlines()[-1],
|
|
icon=STATUS_ICONS[status],
|
|
)
|
|
for index, issue in enumerate(result.issues[: config.MAX_ISSUES_DRAWN]):
|
|
severity = issue.severity or check.severity
|
|
issue_row = col.row(align=True)
|
|
selectable = bool(issue.id_name or issue.elements)
|
|
_wrapped_label(
|
|
issue_row,
|
|
context,
|
|
issue.message,
|
|
icon=SEVERITY_ICONS[severity],
|
|
margin=7 if selectable else 0,
|
|
)
|
|
if selectable:
|
|
op = issue_row.operator(
|
|
"wtd_sanity.select_issues",
|
|
text="",
|
|
icon="RESTRICT_SELECT_OFF",
|
|
emboss=False,
|
|
)
|
|
op.check_id = check.id
|
|
op.issue_index = index
|
|
if check.editable_names:
|
|
id_block = issue.get_id()
|
|
if id_block is not None and id_block.library is None:
|
|
col.prop(id_block, "name", text="", icon="BLANK1")
|
|
hidden = len(result.issues) - config.MAX_ISSUES_DRAWN
|
|
if hidden > 0:
|
|
col.label(text=f"... {hidden} more (see Write Report)", icon="BLANK1")
|
|
col.separator(factor=0.5)
|
|
|
|
|
|
class _SanityPanel:
|
|
bl_region_type = "UI"
|
|
bl_category = "WTD"
|
|
bl_label = "Sanity Check"
|
|
bl_options = {"DEFAULT_CLOSED"} # panel starts collapsed
|
|
|
|
def draw(self, context):
|
|
draw_sanity_checks_panel(self, context)
|
|
|
|
|
|
class _ToolsPanel:
|
|
bl_region_type = "UI"
|
|
bl_category = "WTD"
|
|
bl_label = "Tools"
|
|
|
|
def draw(self, context) -> None:
|
|
layout = self.layout
|
|
layout.operator(
|
|
tools_ops.WTDGetOidForPath.bl_idname,
|
|
text=tools_ops.WTDGetOidForPath.bl_label,
|
|
)
|
|
|
|
# Adds a separator line
|
|
layout.separator()
|
|
|
|
|
|
class _RenamePanel:
|
|
bl_region_type = "UI"
|
|
bl_category = "WTD"
|
|
bl_label = "Rename"
|
|
bl_options = {"DEFAULT_CLOSED"} # panel starts collapsed
|
|
|
|
PREVIEW_COUNT = 10
|
|
|
|
def draw(self, context) -> None:
|
|
layout = self.layout
|
|
settings = context.scene.wtd_rename
|
|
layout.row().prop(settings, "target", expand=True)
|
|
|
|
col = layout.column()
|
|
col.use_property_split = True
|
|
col.use_property_decorate = False
|
|
col.prop(settings, "base_name")
|
|
col.prop(settings, "prefix_mode")
|
|
if settings.prefix_mode == "CUSTOM":
|
|
col.prop(settings, "prefix_custom", text=" ")
|
|
col.prop(settings, "side")
|
|
col.prop(settings, "suffix_mode")
|
|
if settings.suffix_mode == "CUSTOM":
|
|
col.prop(settings, "suffix_custom", text=" ")
|
|
col.prop(settings, "sort")
|
|
if settings.target == "OBJECTS":
|
|
col.prop(settings, "rename_data")
|
|
|
|
plan, skipped = rename.plan_renames(context, settings)
|
|
row = layout.row()
|
|
row.scale_y = 1.4
|
|
row.operator(
|
|
rename.WTD_OT_batch_rename.bl_idname,
|
|
text=f"Rename {len(plan)} Item(s)" if plan else "Rename",
|
|
icon="SORTALPHA",
|
|
)
|
|
if not plan and not skipped:
|
|
return
|
|
box = layout.box()
|
|
col = box.column(align=True)
|
|
for id_block, name in plan[: self.PREVIEW_COUNT]:
|
|
col.label(text=f"{id_block.name} → {name}")
|
|
hidden = len(plan) - self.PREVIEW_COUNT
|
|
if hidden > 0:
|
|
col.label(text=f"... {hidden} more")
|
|
for name in skipped:
|
|
col.label(text=f"{name}: no base name, set a name", icon="ERROR")
|
|
|
|
|
|
class WTD_UL_shots(bpy.types.UIList):
|
|
"""Camera markers of the scene, in time order."""
|
|
|
|
def draw_item(self, context, layout, data, item, icon, active_data, active_property, index=0, flt_flag=0):
|
|
start, end = shot_viewer.shot_range(item)
|
|
split = layout.split(factor=0.4)
|
|
split.label(text=item.name, icon="MARKER_HLT")
|
|
split = split.split(factor=0.6)
|
|
split.label(text=item.camera.name)
|
|
split.label(text=f"{start}-{end}")
|
|
|
|
def filter_items(self, context, data, propname):
|
|
markers = getattr(data, propname)
|
|
ordered = [marker.as_pointer() for marker in shot_viewer.shots(data)]
|
|
position = {pointer: index for index, pointer in enumerate(ordered)}
|
|
flags = [self.bitflag_filter_item if marker.as_pointer() in position else 0 for marker in markers]
|
|
if self.filter_name:
|
|
by_name = bpy.types.UI_UL_list.filter_items_by_name(
|
|
self.filter_name, self.bitflag_filter_item, markers, "name"
|
|
)
|
|
flags = [flag & name_flag for flag, name_flag in zip(flags, by_name)]
|
|
# Shots in time order, the markers without camera after them.
|
|
order = []
|
|
hidden = len(ordered)
|
|
for marker in markers:
|
|
pointer = marker.as_pointer()
|
|
if pointer in position:
|
|
order.append(position[pointer])
|
|
else:
|
|
order.append(hidden)
|
|
hidden += 1
|
|
return flags, order
|
|
|
|
|
|
class _ShotViewerPanel:
|
|
bl_region_type = "UI"
|
|
bl_category = "WTD"
|
|
bl_label = "Shot Viewer"
|
|
|
|
def draw(self, context) -> None:
|
|
layout = self.layout
|
|
settings = context.window_manager.wtd_shot_viewer
|
|
scene = context.scene
|
|
has_shots = bool(shot_viewer.shots(scene))
|
|
|
|
row = layout.row(align=True)
|
|
row.prop(scene, "wtd_sequence")
|
|
row.label(text=shot_viewer.sequence_name(scene))
|
|
|
|
row = layout.row(align=True)
|
|
row.scale_y = 1.4
|
|
row.enabled = has_shots
|
|
row.operator(shot_viewer.WTD_OT_shot_viewer_step.bl_idname, text="Previous", icon="TRIA_LEFT").step = -1
|
|
row.operator(shot_viewer.WTD_OT_shot_viewer_step.bl_idname, text="Next", icon="TRIA_RIGHT").step = 1
|
|
row = layout.row()
|
|
row.template_list("WTD_UL_shots", "", scene, "timeline_markers", settings, "shot_index", rows=5)
|
|
col = row.column(align=True)
|
|
col.operator(shot_viewer.WTD_OT_shot_viewer_new_shot.bl_idname, text="", icon="ADD")
|
|
col.operator(shot_viewer.WTD_OT_shot_viewer_delete_shot.bl_idname, text="", icon="REMOVE")
|
|
if not has_shots:
|
|
layout.label(text="No camera marker yet: add a shot with +", icon="INFO")
|
|
layout.prop(settings, "loop_shot")
|
|
|
|
groups = shot_viewer.rig_groups(context.view_layer)
|
|
if not groups:
|
|
layout.label(text="No rig in the scene", icon="INFO")
|
|
for label, rigs in groups.items():
|
|
box = layout.box()
|
|
box.label(text=label, icon="ARMATURE_DATA")
|
|
col = box.column(align=True)
|
|
for rig in rigs:
|
|
col.operator(
|
|
shot_viewer.WTD_OT_shot_viewer_select_rig.bl_idname,
|
|
text=rig.name,
|
|
depress=rig.select_get(),
|
|
).name = rig.name
|
|
|
|
|
|
MESSAGE_ICONS = {"INFO": "INFO", "WARNING": "ERROR", "ERROR": "CANCEL"}
|
|
|
|
|
|
class _SceneManagerPanel:
|
|
bl_region_type = "UI"
|
|
bl_category = "WTD"
|
|
bl_label = "Scene Manager"
|
|
|
|
def draw(self, context) -> None:
|
|
layout = self.layout
|
|
state = sm.STATE
|
|
scene = context.scene
|
|
|
|
row = layout.row(align=True)
|
|
if sm.connected():
|
|
session = sm.current_session()
|
|
text = f"{session.get('session_name', '?')} ({session.get('cluster_name', '')})"
|
|
if state.ping.get("user"):
|
|
text += f" {state.ping['user']} @ {state.ping.get('site', '')}"
|
|
row.label(text=text, icon="LINKED")
|
|
else:
|
|
row.label(text=state.connection_error, icon="UNLINKED")
|
|
row.operator(sm.WTD_OT_scene_connect.bl_idname, text="", icon="FILE_REFRESH")
|
|
if len(state.sessions) > 1:
|
|
col = layout.column(align=True)
|
|
chosen = context.window_manager.wtd_libreflow.session_uid
|
|
for uid, info in state.sessions.items():
|
|
col.operator(
|
|
sm.WTD_OT_scene_select_session.bl_idname,
|
|
text=f"{info.get('session_name', uid)}: {info.get('current_oid') or ''}",
|
|
depress=uid == chosen,
|
|
).uid = uid
|
|
|
|
layout.prop(scene.wtd_scene_manager, "context_oid", text="", icon="SEQUENCE")
|
|
row = layout.row(align=True)
|
|
row.operator(sm.WTD_OT_scene_use_current_oid.bl_idname, text="Libreflow Oid", icon="IMPORT")
|
|
row.operator(sm.WTD_OT_scene_pick_shot.bl_idname, text="Pick Shot", icon="VIEWZOOM")
|
|
text, valid = sm.context_label(sm.context_oid(scene))
|
|
if text:
|
|
row = layout.row()
|
|
row.alert = not valid
|
|
_wrapped_label(row, context, text, icon="CHECKMARK" if valid else "ERROR")
|
|
|
|
busy = ipc.busy_label()
|
|
if busy:
|
|
layout.label(text=f"{busy}...", icon="SORTTIME")
|
|
message, level = state.message
|
|
if message:
|
|
row = layout.row()
|
|
row.alert = level == "ERROR"
|
|
_wrapped_label(row, context, message, icon=MESSAGE_ICONS[level])
|
|
|
|
|
|
class _SceneCastingPanel:
|
|
bl_region_type = "UI"
|
|
bl_category = "WTD"
|
|
bl_label = "Casting"
|
|
bl_parent_id = "WTD_PT_scene_manager_view3d"
|
|
|
|
def draw(self, context) -> None:
|
|
layout = self.layout
|
|
oid = sm.context_oid(context.scene)
|
|
row = layout.row(align=True)
|
|
row.scale_y = 1.3
|
|
row.operator(sm.WTD_OT_scene_load.bl_idname, text="Load Missing", icon="IMPORT")
|
|
if sm.missing_files(context.scene):
|
|
row.operator(sm.WTD_OT_scene_request.bl_idname, text="Request Missing", icon="URL")
|
|
row.operator(sm.WTD_OT_scene_refresh.bl_idname, text="", icon="FILE_REFRESH")
|
|
casting = sm.STATE.casting.get(oid)
|
|
if casting is None:
|
|
text = "Not read yet: refresh" if sm.is_shot_context(oid) else "Set a shot as context"
|
|
layout.label(text=text, icon="INFO")
|
|
return
|
|
if not casting["assets"]:
|
|
layout.label(text="Nothing cast in this shot", icon="INFO")
|
|
|
|
found = sm_library.all_instances()
|
|
col = layout.column(align=True)
|
|
for asset in casting["assets"]:
|
|
library = sm_library.find_library(asset["file"]["file_oid"]) if asset.get("file") else None
|
|
have = len(found.get(library.name, [])) if library else 0
|
|
want = asset.get("nb_occurences") or 1
|
|
error = asset.get("error")
|
|
file = sm.file_data(asset["file"]["file_oid"], asset["file"]) if asset.get("file") else None
|
|
latest = (file or {}).get("latest") or {}
|
|
requested = bool(error) and latest.get("sync_status") == "Requested"
|
|
if requested:
|
|
error = f"{latest['name']} requested, waiting for the download"
|
|
icon = "SORTTIME" if requested else "ERROR" if error else "CHECKMARK" if have >= want else "IMPORT"
|
|
row = col.row(align=True)
|
|
row.alert = bool(error) and not requested
|
|
row.label(text=f"{asset['name']} ({asset.get('asset_type', '')})", icon=icon)
|
|
row.label(text=f"{have}/{want}")
|
|
if not error and have < want:
|
|
row.operator(sm.WTD_OT_scene_load.bl_idname, text="", icon="IMPORT").asset_oid = asset["oid"]
|
|
if sm.to_request(file):
|
|
row.operator(sm.WTD_OT_scene_request.bl_idname, text="", icon="URL").file_oid = file["file_oid"]
|
|
if error:
|
|
sub = col.row()
|
|
sub.alert = not requested
|
|
_wrapped_label(sub, context, error, icon="BLANK1")
|
|
|
|
cast = {asset["oid"] for asset in casting["assets"]}
|
|
extra = [library for library in sm_library.managed_libraries() if library["wtd_asset_oid"] not in cast]
|
|
if extra:
|
|
box = layout.box()
|
|
box.label(text="Loaded, no longer cast:", icon="ERROR")
|
|
for library in extra:
|
|
box.label(text=library.get("wtd_asset_name", library.name), icon="BLANK1")
|
|
|
|
|
|
class _SceneLoadedPanel:
|
|
bl_region_type = "UI"
|
|
bl_category = "WTD"
|
|
bl_label = "Loaded"
|
|
bl_parent_id = "WTD_PT_scene_manager_view3d"
|
|
|
|
def draw(self, context) -> None:
|
|
layout = self.layout
|
|
libraries = sm_library.managed_libraries()
|
|
if not libraries:
|
|
layout.label(text="Nothing loaded by the Scene Manager", icon="INFO")
|
|
return
|
|
row = layout.row(align=True)
|
|
row.operator(sm.WTD_OT_scene_update.bl_idname, text="Update All", icon="FILE_REFRESH")
|
|
row.operator(sm.WTD_OT_scene_refresh.bl_idname, text="", icon="VIEWZOOM")
|
|
|
|
found = sm_library.all_instances()
|
|
for library in libraries:
|
|
state, text = sm.version_status(library)
|
|
outdated = state in {"UPDATE", "PENDING"}
|
|
expanded = library.name in sm.EXPANDED
|
|
row = layout.row(align=True)
|
|
row.operator(
|
|
sm.WTD_OT_scene_toggle_expand.bl_idname,
|
|
text="",
|
|
emboss=False,
|
|
icon="DOWNARROW_HLT" if expanded else "RIGHTARROW",
|
|
).library = library.name
|
|
row.label(text=library.get("wtd_asset_name", library.name), icon="LIBRARY_DATA_DIRECT")
|
|
version = row.row(align=True)
|
|
version.alert = outdated
|
|
version.label(text=library.get("wtd_revision", "?"))
|
|
if state == "UPDATE":
|
|
row.operator(sm.WTD_OT_scene_update.bl_idname, text="", icon="FILE_REFRESH").library = library.name
|
|
elif state == "PENDING" and sm.to_request(sm.file_data(library["wtd_file_oid"])):
|
|
row.operator(sm.WTD_OT_scene_request.bl_idname, text="", icon="URL").file_oid = library["wtd_file_oid"]
|
|
row.operator(sm.WTD_OT_scene_pick_revision.bl_idname, text="", icon="COLLAPSEMENU").library = library.name
|
|
row.operator(sm.WTD_OT_scene_remove.bl_idname, text="", icon="X").library = library.name
|
|
if outdated:
|
|
sub = layout.row()
|
|
sub.alert = True
|
|
_wrapped_label(sub, context, text, icon="BLANK1")
|
|
if not expanded:
|
|
continue
|
|
col = layout.column(align=True)
|
|
for instance in found.get(library.name, []):
|
|
is_object = isinstance(instance, bpy.types.Object)
|
|
sub = col.row(align=True)
|
|
sub.label(text=instance.name, icon="OUTLINER_OB_EMPTY" if is_object else "OUTLINER_COLLECTION")
|
|
op = sub.operator(sm.WTD_OT_scene_select_instance.bl_idname, text="", icon="RESTRICT_SELECT_OFF")
|
|
op.library, op.instance = library.name, instance.name
|
|
sub.operator(sm.WTD_OT_scene_remove.bl_idname, text="", icon="X").instance = instance.name
|
|
|
|
layout.separator()
|
|
row = layout.row(align=True)
|
|
row.operator(sm.WTD_OT_scene_update.bl_idname, text="Update Selected").selected = True
|
|
row.operator(sm.WTD_OT_scene_remove.bl_idname, text="Remove Selected").selected = True
|
|
|
|
|
|
class _SceneAssetizePanel:
|
|
bl_region_type = "UI"
|
|
bl_category = "WTD"
|
|
bl_label = "Assetize"
|
|
bl_parent_id = "WTD_PT_scene_manager_view3d"
|
|
bl_options = {"DEFAULT_CLOSED"}
|
|
|
|
def draw(self, context) -> None:
|
|
layout = self.layout
|
|
_wrapped_label(
|
|
layout, context, "Publish a local collection of this scene to Libreflow as an asset.", icon="INFO"
|
|
)
|
|
layout.operator(sm.WTD_OT_scene_assetize.bl_idname, text="Assetize Collection...", icon="EXPORT")
|
|
|
|
|
|
class WTD_PT_sanity_view3d(_SanityPanel, bpy.types.Panel):
|
|
bl_idname = "WTD_PT_sanity_view3d"
|
|
bl_space_type = "VIEW_3D"
|
|
|
|
|
|
class WTD_PT_tools_view3d(_ToolsPanel, bpy.types.Panel):
|
|
bl_idname = "WTD_PT_tools_view3d"
|
|
bl_space_type = "VIEW_3D"
|
|
|
|
|
|
class WTD_PT_rename_view3d(_RenamePanel, bpy.types.Panel):
|
|
bl_idname = "WTD_PT_rename_view3d"
|
|
bl_space_type = "VIEW_3D"
|
|
|
|
|
|
class WTD_PT_rename_node_editor(_RenamePanel, bpy.types.Panel):
|
|
bl_idname = "WTD_PT_rename_node_editor"
|
|
bl_space_type = "NODE_EDITOR"
|
|
|
|
|
|
class WTD_PT_shot_viewer_view3d(_ShotViewerPanel, bpy.types.Panel):
|
|
bl_idname = "WTD_PT_shot_viewer_view3d"
|
|
bl_space_type = "VIEW_3D"
|
|
|
|
|
|
class WTD_PT_scene_manager_view3d(_SceneManagerPanel, bpy.types.Panel):
|
|
bl_idname = "WTD_PT_scene_manager_view3d"
|
|
bl_space_type = "VIEW_3D"
|
|
|
|
|
|
class WTD_PT_scene_casting_view3d(_SceneCastingPanel, bpy.types.Panel):
|
|
bl_idname = "WTD_PT_scene_casting_view3d"
|
|
bl_space_type = "VIEW_3D"
|
|
|
|
|
|
class WTD_PT_scene_loaded_view3d(_SceneLoadedPanel, bpy.types.Panel):
|
|
bl_idname = "WTD_PT_scene_loaded_view3d"
|
|
bl_space_type = "VIEW_3D"
|
|
|
|
|
|
class WTD_PT_scene_assetize_view3d(_SceneAssetizePanel, bpy.types.Panel):
|
|
bl_idname = "WTD_PT_scene_assetize_view3d"
|
|
bl_space_type = "VIEW_3D"
|
|
|
|
|
|
class WTD_PT_sanity_sequencer(_SanityPanel, bpy.types.Panel):
|
|
bl_idname = "WTD_PT_sanity_sequencer"
|
|
bl_space_type = "SEQUENCE_EDITOR"
|
|
|
|
|
|
classes = (
|
|
WTD_UL_shots,
|
|
WTD_PT_sanity_view3d,
|
|
WTD_PT_tools_view3d,
|
|
WTD_PT_shot_viewer_view3d,
|
|
WTD_PT_scene_manager_view3d,
|
|
WTD_PT_scene_casting_view3d,
|
|
WTD_PT_scene_loaded_view3d,
|
|
WTD_PT_scene_assetize_view3d,
|
|
WTD_PT_rename_view3d,
|
|
WTD_PT_rename_node_editor,
|
|
WTD_PT_sanity_sequencer,
|
|
)
|
|
|
|
|
|
def register():
|
|
for cls in classes:
|
|
bpy.utils.register_class(cls)
|
|
|
|
|
|
def unregister():
|
|
for cls in reversed(classes):
|
|
bpy.utils.unregister_class(cls)
|