Animation manager improve animated hint
2.3.1 - changed: Animation manager show icons when animation is enabled: fully, partially or not at all.
This commit is contained in:
		
							parent
							
								
									7e92ae182e
								
							
						
					
					
						commit
						798afbe82a
					
				| @ -1,5 +1,9 @@ | ||||
| # Changelog | ||||
| 
 | ||||
| 2.3.1 | ||||
| 
 | ||||
| - changed: Animation manager show hints when animation is enabled: fully, partially or not at all. | ||||
| 
 | ||||
| 2.3.0 | ||||
| 
 | ||||
| - 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 .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 | ||||
| from pathlib import Path | ||||
| from bpy.types import Panel | ||||
| @ -179,48 +182,69 @@ class GPTB_PT_anim_manager(Panel): | ||||
|     # def draw_header(self,context): | ||||
|     #     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): | ||||
|         layout = self.layout | ||||
|         layout.use_property_split = True | ||||
|         col = layout.column() | ||||
|         ## Animation enable disable anim (shift click to select) OP_helpers.GPTB_OT_toggle_mute_animation | ||||
|          | ||||
|         # import time | ||||
|         # 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 | ||||
| 
 | ||||
|         obj_types = self.get_object_by_types(context) | ||||
| 
 | ||||
|         col.operator('gp.list_disabled_anims') | ||||
| 
 | ||||
|         ## Show Enable / Disable | ||||
|         for cat, cat_type, tgt in [('Obj anims:', 'OBJECT', objs), ('Cam anims:', 'CAMERA', cams), ('Gp anims:', 'GPENCIL', gps)]: | ||||
|         ## Show Enable / Disable anims | ||||
|         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.alert = not all_anim_enabled(tgt) # show_alert | ||||
|             # subcol.alert = off_icon == 'LAYER_ACTIVE' # Turn red | ||||
|             row = subcol.row(align=True) | ||||
|             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.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.mute = True | ||||
| 
 | ||||
|         ## GP modifiers | ||||
|         subcol = col.column() | ||||
|         subcol.alert = not all_object_modifier_enabled(gps) # show_alert | ||||
| 
 | ||||
|         row = subcol.row(align=True) | ||||
|         row.label(text='Gp modifiers:') | ||||
|         row.operator('gp.toggle_hide_gp_modifier', text = 'ON').show = True | ||||
|         row.operator('gp.toggle_hide_gp_modifier', text = 'OFF').show = False | ||||
|         on_icon, off_icon = gp_modifier_status(obj_types['GPENCIL']) | ||||
|         # 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 | ||||
|         col = col.column() | ||||
|         row = col.row(align=True) | ||||
|         # row.operator('object.create_follow_path_curve', text='Create Curve', icon='CURVE_BEZCURVE') | ||||
|          | ||||
|         if context.object: | ||||
|             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') | ||||
|         col.prop(context.scene.gptoolprops, 'cursor_follow', text=text, icon=icon) | ||||
|          | ||||
|         # print(f'{time.time() - t0:.6f}s') | ||||
| 
 | ||||
| class GPTB_PT_toolbox_playblast(Panel): | ||||
|     bl_label = "Playblast" | ||||
|  | ||||
| @ -4,7 +4,7 @@ bl_info = { | ||||
| "name": "GP toolbox", | ||||
| "description": "Tool set for Grease Pencil in animation production", | ||||
| "author": "Samuel Bernou, Christophe Seux", | ||||
| "version": (2, 3, 0), | ||||
| "version": (2, 3, 1), | ||||
| "blender": (3, 0, 0), | ||||
| "location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties", | ||||
| "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) | ||||
| 
 | ||||
| 
 | ||||
| ## Not used anymore | ||||
| def all_anim_enabled(objects) -> bool: | ||||
|     '''return False if at least one fcurve/group has disabled animation in passed object anim''' | ||||
|     for o in objects: | ||||
| @ -1146,6 +1147,7 @@ def all_anim_enabled(objects) -> bool: | ||||
| 
 | ||||
|     return True | ||||
| 
 | ||||
| ## Not used anymore | ||||
| 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''' | ||||
|     for o in objects: | ||||
| @ -1158,5 +1160,117 @@ def all_object_modifier_enabled(objects) -> bool: | ||||
|             ## return False when viewport but no render ? | ||||
|             # if not m.show_render and m.show_viewport: | ||||
|                 # 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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user