Load Publish (Loaded panel) searches every asset of the project, then loads any of its published .blend files at any version, cast in the shot or not. The file the casting would load and the latest version on this site are preselected; a version not on this site is requested instead. Built on the existing wtd_list_assets / wtd_get_asset_files / wtd_get_revisions commands. New instances are numbered (COL_bob_01, tree_01...), counting on from the highest number in the file (SCENE_MANAGER_INSTANCE_NAME). README: Pick Shot only lists shots that exist in Libreflow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
604 lines
23 KiB
Python
604 lines
23 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 Manager"
|
|
bl_options = {"DEFAULT_CLOSED"} # panel starts collapsed
|
|
|
|
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
|
|
layout.operator(sm.WTD_OT_scene_browse.bl_idname, text="Load Publish...", icon="VIEWZOOM")
|
|
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
|
|
lods = sm_library.lods(library, instance)
|
|
if lods:
|
|
current = sm_library.current_lod(library, instance)
|
|
sub = col.row(align=True)
|
|
sub.label(text="LOD", icon="BLANK1")
|
|
for name in lods:
|
|
op = sub.operator(sm.WTD_OT_scene_set_lod.bl_idname, text=name, depress=name == current)
|
|
op.lod, op.library, op.instance = name, library.name, 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
|
|
selected = [
|
|
(library, instance)
|
|
for library, instance in sm_library.selected_instances(context.view_layer)
|
|
if sm_library.lods(library, instance)
|
|
]
|
|
if selected:
|
|
col = layout.column(align=True)
|
|
col.label(text="LOD of Selected")
|
|
row = col.row(align=True)
|
|
shown = {sm_library.current_lod(library, instance) for library, instance in selected}
|
|
names = {name for library, instance in selected for name in sm_library.lods(library, instance)}
|
|
for name in sorted(names, key=sm_library.lod_order):
|
|
op = row.operator(sm.WTD_OT_scene_set_lod.bl_idname, text=name, depress=shown == {name})
|
|
op.lod, op.selected = name, 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)
|