2021-01-10 16:47:17 +01:00
|
|
|
import bpy
|
|
|
|
import os
|
|
|
|
from pathlib import Path
|
|
|
|
from .utils import show_message_box, get_addon_prefs
|
|
|
|
|
|
|
|
class GPTB_OT_file_checker(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.file_checker"
|
|
|
|
bl_label = "File check"
|
|
|
|
bl_description = "Check / correct some aspect of the file, properties and such and report"
|
|
|
|
bl_options = {"REGISTER"}
|
|
|
|
|
|
|
|
# @classmethod
|
|
|
|
# def poll(cls, context):
|
|
|
|
# return context.region_data.view_perspective == 'CAMERA'
|
|
|
|
|
|
|
|
## list of action :
|
|
|
|
# Lock main cam:
|
|
|
|
# set scene res
|
|
|
|
# set scene percentage at 100:
|
|
|
|
# set show slider and sync range
|
|
|
|
# set fps
|
|
|
|
# set cursor type
|
|
|
|
# GP use additive drawing (else creating a frame in dopesheet makes it blank...)
|
|
|
|
# GP stroke placement/projection check
|
|
|
|
# Disabled animation
|
|
|
|
# Set onion skin filter to 'All type'
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
prefs = get_addon_prefs()
|
2021-06-17 16:21:27 +02:00
|
|
|
fix = prefs.fixprops
|
2021-01-10 16:47:17 +01:00
|
|
|
problems = []
|
|
|
|
|
|
|
|
## Lock main cam:
|
2021-06-17 16:21:27 +02:00
|
|
|
if fix.lock_main_cam:
|
|
|
|
if not 'layout' in Path(bpy.data.filepath).stem.lower():#dont touch layout cameras
|
|
|
|
if context.scene.camera:
|
|
|
|
cam = context.scene.camera
|
|
|
|
if cam.name == 'draw_cam' and cam.parent:
|
|
|
|
if cam.parent.type == 'CAMERA':
|
|
|
|
cam = cam.parent
|
|
|
|
else:
|
|
|
|
cam = None
|
|
|
|
if cam:
|
|
|
|
triple = (True,True,True)
|
|
|
|
if cam.lock_location[:] != triple or cam.lock_rotation[:] != triple:
|
|
|
|
problems.append('Lock main camera')
|
|
|
|
cam.lock_location = cam.lock_rotation = triple
|
2021-01-10 16:47:17 +01:00
|
|
|
|
|
|
|
## set scene res at pref res according to addon pref
|
2021-06-17 16:21:27 +02:00
|
|
|
if fix.set_scene_res:
|
|
|
|
rx, ry = prefs.render_res_x, prefs.render_res_y
|
|
|
|
# TODO set (rx, ry) to camera resolution if specified in camera name
|
|
|
|
if context.scene.render.resolution_x != rx or context.scene.render.resolution_y != ry:
|
|
|
|
problems.append(f'Resolution {context.scene.render.resolution_x}x{context.scene.render.resolution_y} >> {rx}x{ry}')
|
|
|
|
context.scene.render.resolution_x, context.scene.render.resolution_y = rx, ry
|
2021-01-10 16:47:17 +01:00
|
|
|
|
|
|
|
## set scene percentage at 100:
|
2021-06-17 16:21:27 +02:00
|
|
|
if fix.set_res_percentage:
|
|
|
|
if context.scene.render.resolution_percentage != 100:
|
|
|
|
problems.append('Resolution output to 100%')
|
|
|
|
context.scene.render.resolution_percentage = 100
|
|
|
|
|
|
|
|
## set fps according to preferences settings
|
|
|
|
if fix.set_fps:
|
|
|
|
if context.scene.render.fps != prefs.fps:
|
|
|
|
problems.append( (f"framerate corrected {context.scene.render.fps} >> {prefs.fps}", 'ERROR') )
|
|
|
|
context.scene.render.fps = prefs.fps
|
2021-01-10 16:47:17 +01:00
|
|
|
|
|
|
|
## set show slider and sync range
|
2021-06-17 16:21:27 +02:00
|
|
|
if fix.set_slider_n_sync:
|
|
|
|
for window in bpy.context.window_manager.windows:
|
|
|
|
screen = window.screen
|
|
|
|
for area in screen.areas:
|
|
|
|
if area.type == 'DOPESHEET_EDITOR':
|
|
|
|
if hasattr(area.spaces[0], 'show_sliders'):
|
|
|
|
setattr(area.spaces[0], 'show_sliders', True)
|
2021-01-10 16:47:17 +01:00
|
|
|
|
2021-06-17 16:21:27 +02:00
|
|
|
if hasattr(area.spaces[0], 'show_locked_time'):
|
|
|
|
setattr(area.spaces[0], 'show_locked_time', True)
|
2021-01-10 16:47:17 +01:00
|
|
|
|
2021-06-24 16:40:22 +02:00
|
|
|
## set cursor type
|
|
|
|
if context.mode in ("EDIT_GPENCIL", "SCULPT_GPENCIL"):
|
|
|
|
tool = fix.select_active_tool
|
|
|
|
if tool != 'none':
|
|
|
|
if bpy.context.workspace.tools.from_space_view3d_mode(bpy.context.mode, create=False).idname != tool:
|
|
|
|
bpy.ops.wm.tool_set_by_id(name=tool)# Tweaktoolcode
|
|
|
|
problems.append(f'tool changed to {tool.split(".")[1]}')
|
2021-06-17 16:21:27 +02:00
|
|
|
|
|
|
|
# ## GP use additive drawing (else creating a frame in dopesheet makes it blank...)
|
|
|
|
# if not context.scene.tool_settings.use_gpencil_draw_additive:
|
|
|
|
# problems.append(f'Activated Gp additive drawing mode (snowflake)')
|
|
|
|
# context.scene.tool_settings.use_gpencil_draw_additive = True
|
|
|
|
|
2021-01-10 16:47:17 +01:00
|
|
|
|
|
|
|
## GP stroke placement/projection check
|
2021-06-17 16:21:27 +02:00
|
|
|
if fix.check_front_axis:
|
|
|
|
if context.scene.tool_settings.gpencil_sculpt.lock_axis != 'AXIS_Y':
|
|
|
|
problems.append('/!\\ Draw axis not "Front" (Need Manual change if not Ok)')
|
2021-01-10 16:47:17 +01:00
|
|
|
|
2021-06-17 16:21:27 +02:00
|
|
|
if fix.check_placement:
|
|
|
|
if bpy.context.scene.tool_settings.gpencil_stroke_placement_view3d != 'ORIGIN':
|
|
|
|
problems.append('/!\\ Draw placement not "Origin" (Need Manual change if not Ok)')
|
|
|
|
|
2021-01-10 16:47:17 +01:00
|
|
|
|
|
|
|
## Disabled animation
|
2021-06-17 16:21:27 +02:00
|
|
|
if fix.list_disabled_anim:
|
|
|
|
fcu_ct = 0
|
|
|
|
for act in bpy.data.actions:
|
|
|
|
if not act.users:
|
|
|
|
continue
|
|
|
|
for fcu in act.fcurves:
|
|
|
|
if fcu.mute:
|
|
|
|
fcu_ct += 1
|
|
|
|
print(f"muted: {act.name} > {fcu.data_path}")
|
|
|
|
if fcu_ct:
|
|
|
|
problems.append(f'{fcu_ct} anim channel disabled (details -> console)')
|
|
|
|
|
|
|
|
## Use median point
|
|
|
|
if fix.set_pivot_median_point:
|
|
|
|
if context.scene.tool_settings.transform_pivot_point != 'MEDIAN_POINT':
|
|
|
|
problems.append(f"Pivot changed from '{context.scene.tool_settings.transform_pivot_point}' to 'MEDIAN_POINT'")
|
|
|
|
context.scene.tool_settings.transform_pivot_point = 'MEDIAN_POINT'
|
|
|
|
|
|
|
|
if fix.disable_guide:
|
|
|
|
if context.scene.tool_settings.gpencil_sculpt.guide.use_guide == True:
|
|
|
|
problems.append(f"Disabled Draw Guide")
|
|
|
|
context.scene.tool_settings.gpencil_sculpt.guide.use_guide = False
|
|
|
|
|
|
|
|
if fix.autokey_add_n_replace:
|
|
|
|
if context.scene.tool_settings.auto_keying_mode != 'ADD_REPLACE_KEYS':
|
|
|
|
problems.append(f"Autokey mode reset to 'Add & Replace'")
|
|
|
|
context.scene.tool_settings.auto_keying_mode = 'ADD_REPLACE_KEYS'
|
|
|
|
|
2021-06-28 12:41:56 +02:00
|
|
|
if fix.file_path_type != 'none':
|
|
|
|
pathes = []
|
|
|
|
for p in bpy.utils.blend_paths():
|
|
|
|
if fix.file_path_type == 'RELATIVE':
|
|
|
|
if not p.startswith('//'):
|
|
|
|
pathes.append(p)
|
|
|
|
elif fix.file_path_type == 'ABSOLUTE':
|
|
|
|
if p.startswith('//'):
|
|
|
|
pathes.append(p)
|
|
|
|
if pathes:
|
|
|
|
mess = f'{len(pathes)}/{len(bpy.utils.blend_paths())} paths not {fix.file_path_type.lower()} (see console)'
|
|
|
|
problems.append(mess)
|
|
|
|
print(mess)
|
|
|
|
print('\n'.join(pathes))
|
|
|
|
print('-')
|
|
|
|
|
2021-06-17 16:21:27 +02:00
|
|
|
# ## Set onion skin filter to 'All type'
|
|
|
|
# fix_kf_type = 0
|
|
|
|
# for gp in bpy.data.grease_pencils:#from data
|
|
|
|
# if not gp.is_annotation:
|
|
|
|
# if gp.onion_keyframe_type != 'ALL':
|
|
|
|
# gp.onion_keyframe_type = 'ALL'
|
|
|
|
# fix_kf_type += 1
|
|
|
|
# if fix_kf_type:
|
|
|
|
# problems.append(f"{fix_kf_type} GP onion skin filter to 'All type'")
|
|
|
|
|
2021-01-10 16:47:17 +01:00
|
|
|
# for ob in context.scene.objects:#from object
|
|
|
|
# if ob.type == 'GPENCIL':
|
|
|
|
# ob.data.onion_keyframe_type = 'ALL'
|
|
|
|
|
|
|
|
#### --- print fix/problems report
|
|
|
|
if problems:
|
|
|
|
print('===File check===')
|
|
|
|
for p in problems:
|
|
|
|
if isinstance(p, str):
|
|
|
|
print(p)
|
|
|
|
else:
|
|
|
|
print(p[0])
|
|
|
|
# Show in viewport
|
|
|
|
show_message_box(problems, _title = "Changed Settings", _icon = 'INFO')
|
|
|
|
else:
|
|
|
|
self.report({'INFO'}, 'All good')
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
|
|
|
|
""" OLD links checker with show_message_box
|
|
|
|
class GPTB_OT_links_checker(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.links_checker"
|
|
|
|
bl_label = "Links check"
|
|
|
|
bl_description = "Check states of file direct links"
|
|
|
|
bl_options = {"REGISTER"}
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
all_lnks = []
|
|
|
|
has_broken_link = False
|
|
|
|
## check for broken links
|
|
|
|
for current, lib in zip(bpy.utils.blend_paths(local=True), bpy.utils.blend_paths(absolute=True, local=True)):
|
|
|
|
lfp = Path(lib)
|
|
|
|
realib = Path(current)
|
|
|
|
if not lfp.exists():
|
|
|
|
has_broken_link = True
|
|
|
|
all_lnks.append( (f"Broken link: {realib.as_posix()}", 'LIBRARY_DATA_BROKEN') )#lfp.as_posix()
|
|
|
|
else:
|
|
|
|
if realib.as_posix().startswith('//'):
|
|
|
|
all_lnks.append( (f"Link: {realib.as_posix()}", 'LINKED') )#lfp.as_posix()
|
|
|
|
else:
|
|
|
|
all_lnks.append( (f"Link: {realib.as_posix()}", 'LIBRARY_DATA_INDIRECT') )#lfp.as_posix()
|
|
|
|
|
|
|
|
all_lnks.sort(key=lambda x: x[1], reverse=True)
|
|
|
|
if all_lnks:
|
|
|
|
print('===File check===')
|
|
|
|
for p in all_lnks:
|
|
|
|
if isinstance(p, str):
|
|
|
|
print(p)
|
|
|
|
else:
|
|
|
|
print(p[0])
|
|
|
|
# Show in viewport
|
|
|
|
show_message_box(all_lnks, _title = "Links", _icon = 'INFO')
|
|
|
|
return {"FINISHED"} """
|
|
|
|
|
|
|
|
|
|
|
|
class GPTB_OT_links_checker(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.links_checker"
|
|
|
|
bl_label = "Links check"
|
|
|
|
bl_description = "Check states of file direct links"
|
|
|
|
bl_options = {"REGISTER"}
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
layout = self.layout
|
|
|
|
layout.label(text=self.title)
|
|
|
|
if self.broke_ct:
|
|
|
|
layout.label(text="You can try to scan for missing files:")
|
|
|
|
|
|
|
|
## How to launch directly without filebrowser ?
|
|
|
|
# in Shot folder
|
|
|
|
layout.operator('file.find_missing_files', text='in parent hierarchy').directory = Path(bpy.data.filepath).parents[1].as_posix()
|
|
|
|
if self.proj:
|
|
|
|
# In Library
|
|
|
|
layout.operator('file.find_missing_files', text='in library').directory = (Path(self.proj)/'library').as_posix()
|
|
|
|
# In all project
|
|
|
|
layout.operator('file.find_missing_files', text='in all project (last resort)').directory = self.proj
|
|
|
|
|
|
|
|
|
|
|
|
layout.separator()
|
|
|
|
for l in self.all_lnks:
|
|
|
|
if l[1] == 'LIBRARY_DATA_BROKEN':
|
|
|
|
layout.label(text=l[0], icon=l[1])
|
|
|
|
else:
|
|
|
|
split=layout.split(factor=0.75)
|
|
|
|
split.label(text=l[0], icon=l[1])
|
|
|
|
split.operator('wm.path_open', text='Open folder', icon='FILE_FOLDER').filepath = Path(bpy.path.abspath(l[0])).resolve().parent.as_posix()
|
|
|
|
split.operator('wm.path_open', text='Open file', icon='FILE_TICK').filepath = Path(bpy.path.abspath(l[0])).resolve().as_posix()#os.path.abspath(bpy.path.abspath(dirname(l[0])))
|
|
|
|
|
|
|
|
def invoke(self, context, event):
|
|
|
|
self.all_lnks = []
|
|
|
|
self.title = ''
|
|
|
|
self.broke_ct = 0
|
|
|
|
abs_ct = 0
|
|
|
|
rel_ct = 0
|
|
|
|
## check for broken links
|
|
|
|
for current, lib in zip(bpy.utils.blend_paths(local=True), bpy.utils.blend_paths(absolute=True, local=True)):
|
|
|
|
lfp = Path(lib)
|
|
|
|
realib = Path(current)
|
|
|
|
if not lfp.exists():
|
|
|
|
self.broke_ct += 1
|
|
|
|
self.all_lnks.append( (f"{realib.as_posix()}", 'LIBRARY_DATA_BROKEN') )#lfp.as_posix()
|
|
|
|
else:
|
|
|
|
if realib.as_posix().startswith('//'):
|
|
|
|
rel_ct += 1
|
|
|
|
self.all_lnks.append( (f"{realib.as_posix()}", 'LINKED') )#lfp.as_posix()
|
|
|
|
else:
|
|
|
|
abs_ct += 1
|
|
|
|
self.all_lnks.append( (f"{realib.as_posix()}", 'LIBRARY_DATA_INDIRECT') )#lfp.as_posix()
|
|
|
|
|
|
|
|
if not self.all_lnks:
|
|
|
|
self.report({'INFO'}, 'No external links in files')
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
bct = f"{self.broke_ct} broken " if self.broke_ct else ''
|
|
|
|
act = f"{abs_ct} absolute " if abs_ct else ''
|
|
|
|
rct = f"{rel_ct} clean " if rel_ct else ''
|
|
|
|
|
|
|
|
self.title = f"{bct}{act}{rct}"
|
|
|
|
|
|
|
|
self.all_lnks.sort(key=lambda x: x[1], reverse=True)
|
|
|
|
if self.all_lnks:
|
|
|
|
print('===File check===')
|
|
|
|
for p in self.all_lnks:
|
|
|
|
if isinstance(p, str):
|
|
|
|
print(p)
|
|
|
|
else:
|
|
|
|
print(p[0])
|
|
|
|
# Show in viewport
|
|
|
|
|
|
|
|
# if broke_ct == 0:
|
|
|
|
# show_message_box(self.all_lnks, _title = self.title, _icon = 'INFO')# Links
|
|
|
|
# return {"FINISHED"}
|
|
|
|
try:
|
|
|
|
self.proj = context.preferences.addons['pipe_sync'].preferences['local_folder']
|
|
|
|
except:
|
|
|
|
self.proj = None
|
|
|
|
return context.window_manager.invoke_props_dialog(self, width=800)
|
|
|
|
|
|
|
|
'''### OLD
|
|
|
|
class GPTB_OT_check_scene(bpy.types.Operator):
|
|
|
|
bl_idname = "gp.scene_check"
|
|
|
|
bl_label = "Check GP scene"
|
|
|
|
bl_description = "Check and fix scene settings"
|
|
|
|
bl_options = {"REGISTER"}
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def poll(cls, context):
|
|
|
|
return True
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
## check scene resolution / 100% / framerate
|
|
|
|
context.scene.render.resolution_percentage = 100
|
|
|
|
context.scene.render.resolution_x = 3072# define addon properties to make generic ?
|
|
|
|
context.scene.render.resolution_y = 1620# define addon properties to make generic ?
|
|
|
|
context.scene.render.fps = 24# define addon properties to make generic ?
|
|
|
|
|
|
|
|
## check GP datas name
|
|
|
|
gp_os = [o for o in context.scene.objects if o.type == 'GPENCIL' if o.data.users == 1]#no multiple users
|
|
|
|
|
|
|
|
for gpo in gp_os:
|
|
|
|
if gpo.data.name.startswith('Stroke'):# dont touch already renamed group
|
|
|
|
if gpo.data.name != gpo.name:
|
|
|
|
print('renaming GP data:', gpo.data.name, '-->', gpo.name)
|
|
|
|
gpo.data.name = gpo.name
|
|
|
|
|
|
|
|
## disable autolock
|
|
|
|
context.scene.tool_settings.lock_object_mode = False
|
|
|
|
|
|
|
|
return {"FINISHED"}
|
|
|
|
'''
|
|
|
|
|
|
|
|
classes = (
|
|
|
|
# GPTB_OT_check_scene,
|
|
|
|
GPTB_OT_file_checker,
|
|
|
|
GPTB_OT_links_checker,
|
|
|
|
)
|
|
|
|
|
|
|
|
def register():
|
|
|
|
for cls in classes:
|
|
|
|
bpy.utils.register_class(cls)
|
|
|
|
|
|
|
|
def unregister():
|
|
|
|
for cls in reversed(classes):
|
|
|
|
bpy.utils.unregister_class(cls)
|