Animation manager improve animated hint
2.3.1 - changed: Animation manager show icons when animation is enabled: fully, partially or not at all.gpv2
parent
7e92ae182e
commit
798afbe82a
|
@ -1,5 +1,9 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
2.3.1
|
||||||
|
|
||||||
|
- changed: Animation manager show hints when animation is enabled: fully, partially or not at all.
|
||||||
|
|
||||||
2.3.0
|
2.3.0
|
||||||
|
|
||||||
- added: Animation manager buttons are colored red when objects have disabled animation
|
- added: Animation manager buttons are colored red when objects have disabled animation
|
||||||
|
|
61
UI_tools.py
61
UI_tools.py
|
@ -1,5 +1,8 @@
|
||||||
# from . import addon_updater_ops
|
# from . import addon_updater_ops
|
||||||
from .utils import get_addon_prefs, all_anim_enabled, all_object_modifier_enabled
|
from .utils import (get_addon_prefs,
|
||||||
|
anim_status,
|
||||||
|
gp_modifier_status,
|
||||||
|
)
|
||||||
import bpy
|
import bpy
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from bpy.types import Panel
|
from bpy.types import Panel
|
||||||
|
@ -179,48 +182,69 @@ class GPTB_PT_anim_manager(Panel):
|
||||||
# def draw_header(self,context):
|
# def draw_header(self,context):
|
||||||
# self.layout.prop(context.scene.camera.data, "show_background_images", text="")
|
# self.layout.prop(context.scene.camera.data, "show_background_images", text="")
|
||||||
|
|
||||||
|
def get_object_by_types(self, context) -> dict:
|
||||||
|
# import time
|
||||||
|
# t0 = time.perf_counter()
|
||||||
|
|
||||||
|
# objs = [o for o in context.scene.objects if o.type not in ('GPENCIL', 'CAMERA')]
|
||||||
|
# gps = [o for o in context.scene.objects if o.type == 'GPENCIL']
|
||||||
|
# cams = [o for o in context.scene.objects if o.type == 'CAMERA']
|
||||||
|
objs = []
|
||||||
|
gps = []
|
||||||
|
cams = []
|
||||||
|
for o in context.scene.objects:
|
||||||
|
if o.type not in ('GPENCIL', 'CAMERA'):
|
||||||
|
objs.append(o)
|
||||||
|
elif o.type == 'GPENCIL':
|
||||||
|
gps.append(o)
|
||||||
|
elif o.type == 'CAMERA':
|
||||||
|
cams.append(o)
|
||||||
|
|
||||||
|
# print(f'{time.perf_counter() - t0:.8f}s')
|
||||||
|
|
||||||
|
return {'OBJECT': objs, 'GPENCIL': gps, 'CAMERA': cams}
|
||||||
|
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
layout.use_property_split = True
|
layout.use_property_split = True
|
||||||
col = layout.column()
|
col = layout.column()
|
||||||
## Animation enable disable anim (shift click to select) OP_helpers.GPTB_OT_toggle_mute_animation
|
## Animation enable disable anim (shift click to select) OP_helpers.GPTB_OT_toggle_mute_animation
|
||||||
|
|
||||||
# import time
|
obj_types = self.get_object_by_types(context)
|
||||||
# t0 = time.time()
|
|
||||||
|
|
||||||
scn = context.scene
|
|
||||||
objs = [o for o in scn.objects if o.type not in ('GPENCIL', 'CAMERA')] # show_alert
|
|
||||||
gps = [o for o in scn.objects if o.type == 'GPENCIL'] # show_alert
|
|
||||||
cams = [o for o in scn.objects if o.type == 'CAMERA'] # show_alert
|
|
||||||
|
|
||||||
col.operator('gp.list_disabled_anims')
|
col.operator('gp.list_disabled_anims')
|
||||||
|
|
||||||
## Show Enable / Disable
|
## Show Enable / Disable anims
|
||||||
for cat, cat_type, tgt in [('Obj anims:', 'OBJECT', objs), ('Cam anims:', 'CAMERA', cams), ('Gp anims:', 'GPENCIL', gps)]:
|
for cat, cat_type in [('Obj anims:', 'OBJECT'), ('Cam anims:', 'CAMERA'), ('Gp anims:', 'GPENCIL')]:
|
||||||
|
on_icon, off_icon = anim_status(obj_types[cat_type])
|
||||||
|
|
||||||
subcol = col.column()
|
subcol = col.column()
|
||||||
subcol.alert = not all_anim_enabled(tgt) # show_alert
|
# subcol.alert = off_icon == 'LAYER_ACTIVE' # Turn red
|
||||||
row = subcol.row(align=True)
|
row = subcol.row(align=True)
|
||||||
row.label(text=cat)
|
row.label(text=cat)
|
||||||
ops = row.operator('gp.toggle_mute_animation', text = 'ON')
|
|
||||||
|
ops = row.operator('gp.toggle_mute_animation', text='ON', icon=on_icon)
|
||||||
ops.mode = cat_type
|
ops.mode = cat_type
|
||||||
ops.mute = False
|
ops.mute = False
|
||||||
|
|
||||||
ops = row.operator('gp.toggle_mute_animation', text = 'OFF')
|
ops = row.operator('gp.toggle_mute_animation', text='OFF', icon=off_icon)
|
||||||
ops.mode = cat_type
|
ops.mode = cat_type
|
||||||
ops.mute = True
|
ops.mute = True
|
||||||
|
|
||||||
## GP modifiers
|
## GP modifiers
|
||||||
subcol = col.column()
|
subcol = col.column()
|
||||||
subcol.alert = not all_object_modifier_enabled(gps) # show_alert
|
|
||||||
row = subcol.row(align=True)
|
row = subcol.row(align=True)
|
||||||
row.label(text='Gp modifiers:')
|
row.label(text='Gp modifiers:')
|
||||||
row.operator('gp.toggle_hide_gp_modifier', text = 'ON').show = True
|
on_icon, off_icon = gp_modifier_status(obj_types['GPENCIL'])
|
||||||
row.operator('gp.toggle_hide_gp_modifier', text = 'OFF').show = False
|
# subcol.alert = off_icon == 'LAYER_ACTIVE' # Turn red
|
||||||
|
row.operator('gp.toggle_hide_gp_modifier', text='ON', icon=on_icon).show = True
|
||||||
|
row.operator('gp.toggle_hide_gp_modifier', text='OFF', icon=off_icon).show = False
|
||||||
|
|
||||||
## Follow curve path
|
## Follow curve path
|
||||||
col = col.column()
|
col = col.column()
|
||||||
row = col.row(align=True)
|
row = col.row(align=True)
|
||||||
# row.operator('object.create_follow_path_curve', text='Create Curve', icon='CURVE_BEZCURVE')
|
|
||||||
|
|
||||||
if context.object:
|
if context.object:
|
||||||
if context.object.type == 'CURVE' and context.mode in ('OBJECT', 'EDIT_CURVE'):
|
if context.object.type == 'CURVE' and context.mode in ('OBJECT', 'EDIT_CURVE'):
|
||||||
|
@ -248,7 +272,6 @@ class GPTB_PT_anim_manager(Panel):
|
||||||
text, icon = ('Cursor Follow On', 'PIVOT_CURSOR') if context.scene.gptoolprops.cursor_follow else ('Cursor Follow Off', 'CURSOR')
|
text, icon = ('Cursor Follow On', 'PIVOT_CURSOR') if context.scene.gptoolprops.cursor_follow else ('Cursor Follow Off', 'CURSOR')
|
||||||
col.prop(context.scene.gptoolprops, 'cursor_follow', text=text, icon=icon)
|
col.prop(context.scene.gptoolprops, 'cursor_follow', text=text, icon=icon)
|
||||||
|
|
||||||
# print(f'{time.time() - t0:.6f}s')
|
|
||||||
|
|
||||||
class GPTB_PT_toolbox_playblast(Panel):
|
class GPTB_PT_toolbox_playblast(Panel):
|
||||||
bl_label = "Playblast"
|
bl_label = "Playblast"
|
||||||
|
|
|
@ -4,7 +4,7 @@ bl_info = {
|
||||||
"name": "GP toolbox",
|
"name": "GP toolbox",
|
||||||
"description": "Tool set for Grease Pencil in animation production",
|
"description": "Tool set for Grease Pencil in animation production",
|
||||||
"author": "Samuel Bernou, Christophe Seux",
|
"author": "Samuel Bernou, Christophe Seux",
|
||||||
"version": (2, 3, 0),
|
"version": (2, 3, 1),
|
||||||
"blender": (3, 0, 0),
|
"blender": (3, 0, 0),
|
||||||
"location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
|
"location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
|
||||||
"warning": "",
|
"warning": "",
|
||||||
|
|
116
utils.py
116
utils.py
|
@ -1119,6 +1119,7 @@ def go_edit_mode(ob, context=None):
|
||||||
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
|
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
|
||||||
|
|
||||||
|
|
||||||
|
## Not used anymore
|
||||||
def all_anim_enabled(objects) -> bool:
|
def all_anim_enabled(objects) -> bool:
|
||||||
'''return False if at least one fcurve/group has disabled animation in passed object anim'''
|
'''return False if at least one fcurve/group has disabled animation in passed object anim'''
|
||||||
for o in objects:
|
for o in objects:
|
||||||
|
@ -1146,6 +1147,7 @@ def all_anim_enabled(objects) -> bool:
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
## Not used anymore
|
||||||
def all_object_modifier_enabled(objects) -> bool:
|
def all_object_modifier_enabled(objects) -> bool:
|
||||||
'''Return False if one modifier of one object has GP modifier disabled in viewport but enabled in render'''
|
'''Return False if one modifier of one object has GP modifier disabled in viewport but enabled in render'''
|
||||||
for o in objects:
|
for o in objects:
|
||||||
|
@ -1158,5 +1160,117 @@ def all_object_modifier_enabled(objects) -> bool:
|
||||||
## return False when viewport but no render ?
|
## return False when viewport but no render ?
|
||||||
# if not m.show_render and m.show_viewport:
|
# if not m.show_render and m.show_viewport:
|
||||||
# return False
|
# return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
## Only used in anim_status in 'per GP object' mode
|
||||||
|
def has_fully_enabled_anim(o):
|
||||||
|
if o.animation_data and o.animation_data.action:
|
||||||
|
## Skip hided object ? (missmatch)
|
||||||
|
# if o.hide_get():
|
||||||
|
# continue
|
||||||
|
|
||||||
|
## Check if groups are muted
|
||||||
|
for grp in o.animation_data.action.groups:
|
||||||
|
if grp.mute:
|
||||||
|
return False
|
||||||
|
|
||||||
|
## Check if fcurves are muted
|
||||||
|
for fcu in o.animation_data.action.fcurves:
|
||||||
|
if fcu.mute:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if o.type in ('GPENCIL', 'CAMERA'):
|
||||||
|
if o.data.animation_data and o.data.animation_data.action:
|
||||||
|
## Check if object data attributes fcurves are muted
|
||||||
|
for fcu in o.animation_data.action.fcurves:
|
||||||
|
if fcu.mute:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def anim_status(objects) -> tuple((str, str)):
|
||||||
|
'''Return a tutple of icon string status in ('ALL_ON', 'MIXED', 'ALL_OFF', 'NONE')'''
|
||||||
|
|
||||||
return True
|
on_count = off_count = count = 0
|
||||||
|
|
||||||
|
for o in objects:
|
||||||
|
## Skip object with no animation
|
||||||
|
if not (o.animation_data and o.animation_data.action) and not (o.data.animation_data and o.data.animation_data.action):
|
||||||
|
continue
|
||||||
|
|
||||||
|
## Also skip hidden objects
|
||||||
|
if o.hide_get() and o.hide_render:
|
||||||
|
continue
|
||||||
|
|
||||||
|
### Per Object
|
||||||
|
# count += 1
|
||||||
|
# if has_fully_enabled_anim(o):
|
||||||
|
# on_count += 1
|
||||||
|
# else:
|
||||||
|
# off_count += 1
|
||||||
|
|
||||||
|
### Consider All channels individually
|
||||||
|
for grp in o.animation_data.action.groups:
|
||||||
|
## Check if groups are muted
|
||||||
|
if grp.mute:
|
||||||
|
off_count += 1
|
||||||
|
else:
|
||||||
|
on_count += 1
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
|
||||||
|
for fcu in o.animation_data.action.fcurves:
|
||||||
|
## Check if fcurves are muted
|
||||||
|
if fcu.mute:
|
||||||
|
off_count += 1
|
||||||
|
else:
|
||||||
|
on_count += 1
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
if o.type in ('GPENCIL', 'CAMERA'):
|
||||||
|
if o.data.animation_data and o.data.animation_data.action:
|
||||||
|
## Check if object data attributes fcurves are muted
|
||||||
|
for fcu in o.animation_data.action.fcurves:
|
||||||
|
if fcu.mute:
|
||||||
|
off_count += 1
|
||||||
|
else:
|
||||||
|
on_count += 1
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
if not on_count and not off_count:
|
||||||
|
return ('BLANK1', 'BLANK1') # 'NONE'
|
||||||
|
elif on_count == count:
|
||||||
|
return ('LAYER_ACTIVE', 'BLANK1') # 'ALL_ON'
|
||||||
|
elif off_count == count:
|
||||||
|
return ('BLANK1', 'LAYER_ACTIVE') # 'ALL_OFF'
|
||||||
|
else:
|
||||||
|
return ('LAYER_USED', 'LAYER_USED') # 'MIXED'
|
||||||
|
|
||||||
|
|
||||||
|
def gp_modifier_status(objects) -> tuple((str, str)):
|
||||||
|
'''return icons on/off tuple'''
|
||||||
|
on_count = off_count = count = 0
|
||||||
|
for o in objects:
|
||||||
|
if o.type != 'GPENCIL':
|
||||||
|
continue
|
||||||
|
## Skip hided object
|
||||||
|
if o.hide_get() and o.hide_render:
|
||||||
|
continue
|
||||||
|
for m in o.grease_pencil_modifiers:
|
||||||
|
if m.show_render and not m.show_viewport:
|
||||||
|
off_count += 1
|
||||||
|
else:
|
||||||
|
on_count += 1
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
## return False when viewport but no render ?
|
||||||
|
# if not m.show_render and m.show_viewport:
|
||||||
|
# return False
|
||||||
|
|
||||||
|
if not on_count and not off_count:
|
||||||
|
return ('BLANK1', 'BLANK1') # 'NONE'
|
||||||
|
elif on_count == count:
|
||||||
|
return ('LAYER_ACTIVE', 'BLANK1') # 'ALL_ON'
|
||||||
|
elif off_count == count:
|
||||||
|
return ('BLANK1', 'LAYER_ACTIVE') # 'ALL_OFF'
|
||||||
|
else:
|
||||||
|
return ('LAYER_USED', 'LAYER_USED')
|
Loading…
Reference in New Issue