# from . import addon_updater_ops from .utils import (get_addon_prefs, anim_status, gp_modifier_status, ) import bpy from pathlib import Path from bpy.types import Panel ## UI in properties ### dataprop_panel not used --> transferred to sidebar """ class GPTB_PT_dataprop_panel(Panel): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' # bl_space_type = 'VIEW_3D' # bl_region_type = 'UI' # bl_category = "Tool" # bl_idname = "ADDONID_PT_panel_name"# identifier, if ommited, takes the name of the class. bl_label = "Pseudo color"# title bl_parent_id = "DATA_PT_grease_pencil_layers"#subpanel of this ID bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout layout.use_property_split = True settings = context.scene.gptoolprops col = layout.column(align = True) row = col.split(align=False, factor=0.63) row.prop(settings, 'autotint_offset') row.prop(settings, 'autotint_namespace') col.operator("gp.auto_tint_gp_layers", icon = "COLOR").reset = False col.operator("gp.auto_tint_gp_layers", text = "Reset tint", icon = "COLOR").reset = True """ ## UI in Gpencil sidebar menu class GPTB_PT_sidebar_panel(Panel): bl_label = "GP Toolbox" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Gpencil" def draw(self, context): layout = self.layout # layout.use_property_split = True prefs = get_addon_prefs() rd = context.scene.render # check for update # addon_updater_ops.check_for_update_background() # layout.label(text='View options:') col = layout.column() ## flip X cam # layout.label(text='! Flipped !') row = col.row(align=True) row.prop(context.scene.tool_settings, 'gpencil_stroke_placement_view3d', text='') row.prop(context.scene.tool_settings.gpencil_sculpt, 'lock_axis', text='') row = col.row(align=True) row.operator('view3d.camera_mirror_flipx', text = 'Mirror Flip', icon = 'MOD_MIRROR')# ARROW_LEFTRIGHT if context.scene.camera and context.scene.camera.scale.x < 0: row.label(text='',icon='LOOP_BACK') ## draw/manipulation camera if context.scene.camera and context.scene.camera.name.startswith(('draw', 'obj')): row = col.row(align=True) row.operator('gp.draw_cam_switch', text = 'Main cam', icon = 'OUTLINER_OB_CAMERA') row.label(text='',icon='LOOP_BACK') if context.scene.camera.name.startswith('draw'): col.operator('gp.reset_cam_rot', text='reset rotation')#.swapmethod ? = CAM else: col.operator('gp.set_view_as_cam', text='set view')#.swapmethod ? = CAM else: row = col.row(align=True) row.operator('gp.draw_cam_switch', text = 'Draw cam', icon = 'CON_CAMERASOLVER').cam_mode = 'draw' row.operator('gp.draw_cam_switch', text = 'Object cam', icon = 'CON_CAMERASOLVER').cam_mode = 'object' col.label(text='In main camera', icon = 'OUTLINER_OB_CAMERA') # layout.operator('gp.overlay_presets', text = 'Toggle overlays', icon = 'OVERLAY') if context.scene.camera: row = layout.row(align=True)# .split(factor=0.5) row.label(text='Passepartout') if context.scene.camera.name == 'draw_cam': row.prop(context.scene.gptoolprops, 'drawcam_passepartout', text='', icon ='OBJECT_HIDDEN') else: row.prop(context.scene.camera.data, 'show_passepartout', text='', icon ='OBJECT_HIDDEN') row.prop(context.scene.camera.data, 'passepartout_alpha', text='') # row = layout.row(align=True) # row.operator('view3d.view_camera_frame_fit', text = 'Custom fit', icon = 'ZOOM_PREVIOUS') # FULLSCREEN_EXIT row = layout.row(align=True) row.operator('view3d.zoom_camera_1_to_1', text = 'Zoom 1:1', icon = 'ZOOM_PREVIOUS') # FULLSCREEN_EXIT row.operator('view3d.view_center_camera', text = 'Zoom fit', icon = 'FULLSCREEN_ENTER') ## background images/videos if context.scene.camera.data.background_images: layout.separator() icon_bg = 'RESTRICT_VIEW_OFF' if context.scene.camera.data.show_background_images else 'RESTRICT_VIEW_ON'# IMAGE_BACKGROUND#IMAGE_PLANE # icon_bg = 'TRIA_DOWN' if context.scene.camera.data.show_background_images else 'IMAGE_BACKGROUND' box = layout.box() box.prop(context.scene.camera.data, 'show_background_images', text='Ref in cam', icon=icon_bg) if context.scene.camera.data.show_background_images: # box = layout.box() for bg_img in context.scene.camera.data.background_images: if bg_img.source == 'IMAGE' and bg_img.image: row = box.row(align=True) row.prop(bg_img, 'show_background_image', text='', icon='IMAGE_RGB') row.prop(bg_img, 'alpha', text=bg_img.image.name) # options={'HIDDEN'} # row.label(icon='IMAGE_RGB') # icon = 'HIDE_OFF' if bg_img.show_background_image else 'HIDE_ON' # row.prop(bg_img, 'show_background_image', text='', icon=icon) if bg_img.source == 'MOVIE_CLIP' and bg_img.clip: row = box.row(align=True) row.prop(bg_img, 'show_background_image', text='', icon='FILE_MOVIE') row.prop(bg_img, 'alpha', text=bg_img.clip.name) # options={'HIDDEN'} # row.label(icon='FILE_MOVIE') # icon = 'HIDE_OFF' if bg_img.show_background_image else 'HIDE_ON' # row.prop(bg_img, 'show_background_image', text='', icon=icon) else: layout.label(text='No camera !', icon = 'ERROR') ## Straight line ops from official greasepencil_tools addon if enabled. # if any(x in context.preferences.addons.keys() for x in ('greasepencil_tools', 'greasepencil-addon')): # check enabled addons if hasattr(bpy.types, 'GP_OT_straight_stroke'): # check if operator exists : bpy.ops.gp.straight_stroke.idname() layout.operator(bpy.types.GP_OT_straight_stroke.bl_idname, icon ="CURVE_PATH") ## Options col = layout.column() col.label(text = 'Options:') ## Kf Jump filter col.prop(context.scene.gptoolprops, 'keyframe_type', text='Jump On') # Keyframe Jump # col.prop(context.space_data.overlay, 'use_gpencil_onion_skin') # not often used if context.object and context.object.type == 'GREASEPENCIL': # col.prop(context.object.data, 'use_autolock_layers') # not often used col.prop(context.object, 'show_in_front') # text='In Front' ## rename datablock temporary layout if context.object.name != context.object.data.name: box = col.box() box.label(text='different name for object and data:', icon='INFO') row = box.row(align=False) row.operator('gp.rename_data_from_obj').rename_all = False row.operator('gp.rename_data_from_obj', text='Rename all').rename_all = True ## Check base palette if prefs.warn_base_palette and prefs.palette_path: if not all(x in [m.name for m in context.object.data.materials if m] for x in ("line", "invisible")): box = col.box() box.label(text='Missing base material setup', icon='INFO') box.operator('gp.load_default_palette') else: col.label(text='No GP object selected') ## Gpv3: not more edit line (use Curve lines) # col.prop(context.scene.gptoolprops, 'edit_lines_opacity') # Mention update as notice # addon_updater_ops.update_notice_box_ui(self, context) # row = layout.row(align=False) # row.label(text='arrow choice') # row.operator("my_operator.multi_op", text='', icon='TRIA_LEFT').left = 1 # row.operator("my_operator.multi_op", text='', icon='TRIA_RIGHT').left = 0 class GPTB_PT_anim_manager(Panel): bl_label = "Animation Manager" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Gpencil" bl_parent_id = "GPTB_PT_sidebar_panel" bl_options = {'DEFAULT_CLOSED'} # 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 ('GREASEPENCIL', 'CAMERA')] # gps = [o for o in context.scene.objects if o.type == 'GREASEPENCIL'] # 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 ('GREASEPENCIL', 'CAMERA'): objs.append(o) elif o.type == 'GREASEPENCIL': gps.append(o) elif o.type == 'CAMERA': cams.append(o) # print(f'{time.perf_counter() - t0:.8f}s') return {'OBJECT': objs, 'GREASEPENCIL': 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 obj_types = self.get_object_by_types(context) col.operator('gp.list_disabled_anims') ## Show Enable / Disable anims for cat, cat_type in [('Obj anims:', 'OBJECT'), ('Cam anims:', 'CAMERA'), ('Gp anims:', 'GREASEPENCIL')]: on_icon, off_icon = anim_status(obj_types[cat_type]) subcol = col.column() # 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', icon=on_icon) ops.mode = cat_type ops.mute = False ops = row.operator('gp.toggle_mute_animation', text='OFF', icon=off_icon) ops.mode = cat_type ops.mute = True ## GP modifiers subcol = col.column() row = subcol.row(align=True) row.label(text='Gp modifiers:') on_icon, off_icon = gp_modifier_status(obj_types['GREASEPENCIL']) # 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 ## Step Select Frames col.operator('gptb.step_select_frames') ## Follow curve path col = col.column() row = col.row(align=True) if context.object: if context.object.type == 'CURVE' and context.mode in ('OBJECT', 'EDIT_CURVE'): row.operator('object.object_from_curve', text='Back To Object', icon='LOOP_BACK') elif (follow_const := context.object.constraints.get('Follow Path')) and follow_const.target: row.operator('object.edit_curve', text='Edit Curve', icon='OUTLINER_DATA_CURVE') row.operator('object.remove_follow_path', text='', icon='X') col.label(text=f'{context.object.name} -> {follow_const.target.name}', icon='CON_FOLLOWPATH') if follow_const.use_fixed_location: col.prop(follow_const, 'offset_factor') else: col.prop(follow_const, 'offset') if context.object.location.length != 0: # context.object.location[:] != (0,0,0): col.operator('object.location_clear', text='Offseted Location! Reset', icon='ERROR') # ? Check if object location is animated ? (can be intentional...) else: col.operator('object.create_follow_path_curve', text='Create Follow Curve', icon='CURVE_BEZCURVE') ## This can go in an extra category... col = layout.column() col.use_property_split = False 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) if context.scene.gptoolprops.cursor_follow: col.prop(context.scene.gptoolprops, 'cursor_follow_target', text='Target', icon='OBJECT_DATA') class GPTB_PT_toolbox_playblast(Panel): bl_label = "Playblast" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Gpencil" bl_parent_id = "GPTB_PT_sidebar_panel" bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout rd = context.scene.render row = layout.row(align=False) # split(factor=0.6) percent = context.scene.gptoolprops.resolution_percentage row.label(text = f'{rd.resolution_x * percent // 100} x {rd.resolution_y * percent // 100}') row.prop(context.scene.gptoolprops, 'resolution_percentage', text='') # row.prop(rd, 'resolution_percentage', text='') # real percent scene percentage row = layout.row(align=True) row.operator('render.thread_playblast', text = 'Playblast', icon = 'RENDER_ANIMATION')# non blocking background render playblast # row.operator('render.playblast_anim', text = 'Playblast', icon = 'RENDER_ANIMATION').use_view = False # old (but robust) blocking playblast row.operator('render.playblast_anim', text = 'Viewport').use_view = True class GPTB_PT_tint_layers(Panel): bl_label = "Tint Layers" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Gpencil" bl_parent_id = "GPTB_PT_sidebar_panel" bl_options = {'DEFAULT_CLOSED'} # def draw_header(self,context): # self.layout.prop(context.scene.camera.data, "show_background_images", text="") def draw(self, context): layout = self.layout layout.use_property_split = True ## pseudo color layers # layout.separator() col = layout.column(align = True) # row = col.split(align=False, factor=0.63) # row = col.row() col.prop(context.scene.gptoolprops, 'autotint_offset', text='Hue Offset') col.prop(context.scene.gptoolprops, 'autotint_namespace') col.operator("gp.auto_tint_gp_layers", icon = "COLOR").reset = False col.operator("gp.auto_tint_gp_layers", text = "Reset tint", icon = "COLOR").reset = True class GPTB_PT_checker(Panel): bl_label = "Checker" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Gpencil" bl_parent_id = "GPTB_PT_sidebar_panel" bl_options = {'DEFAULT_CLOSED'} # def draw_header(self,context): # self.layout.prop(context.scene.camera.data, "show_background_images", text="") def draw(self, context): layout = self.layout col = layout.column() row = col.row(align=True) ## realign / reproject row.operator('gp.realign', icon='AXIS_FRONT') ## move in depth row.operator('object.depth_proportional_move', text='Depth move', icon='TRANSFORM_ORIGINS') ## col.operator('gp.batch_reproject_all_frames') # text=Batch Reproject # added to context menu ## check drawing alignement col.operator('gp.check_canvas_alignement', icon='DRIVER_ROTATIONAL_DIFFERENCE') ## File checker row = col.row(align=True) row.operator('gp.file_checker', text = 'Check file', icon = 'SCENE_DATA') row.operator('gp.links_checker', text = 'Check links', icon = 'UNLINKED') class GPTB_PT_color(Panel): bl_label = "Color" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Gpencil" bl_parent_id = "GPTB_PT_sidebar_panel" bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout col = layout.column() ## Create empty frame on layer # Material panel as a pop-up (would work if palette dir is separated) # col.operator("wm.call_panel", text="Link Materials Palette", icon='COLOR').name = "GPTB_PT_palettes_linker_ui" col.operator('gp.create_empty_frames', icon='DECORATE_KEYFRAME') # col.operator("wm.call_panel", text="Link Material Palette", icon='COLOR').name = "GPTB_PT_palettes_list_popup" """ # unused : added in Animation Manager class GPTB_PT_extra(Panel): bl_label = "Extra" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Gpencil" bl_parent_id = "GPTB_PT_sidebar_panel" bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout col = layout.column() 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) """ """ ## unused -- (integrated in sidebar_panel) class GPTB_PT_cam_ref_panel(Panel): bl_label = "Background imgs" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Gpencil" bl_parent_id = "GPTB_PT_sidebar_panel" @classmethod def poll(cls, context): return context.scene.camera def draw_header(self,context): self.layout.prop(context.scene.camera.data, "show_background_images", text="") def draw(self, context): layout = self.layout layout.use_property_split = True if context.scene.camera.data.show_background_images: for bg_img in context.scene.camera.data.background_images: if bg_img.image: row = layout.row(align=False) row.label(text=bg_img.image.name, icon='IMAGE_RGB') row.prop(bg_img, 'show_background_image', text='')# options={'HIDDEN'} """ def palette_manager_menu(self, context): """Palette menu to append in existing menu""" # GPENCIL_MT_material_context_menu layout = self.layout # {'EDIT_GREASE_PENCIL', 'PAINT_GREASE_PENCIL','SCULPT_GREASE_PENCIL','WEIGHT_GREASE_PENCIL', 'VERTEX_GPENCIL'} layout.separator() prefs = get_addon_prefs() layout.operator("gp.copy_active_to_selected_palette", text='Append Materials To Selected', icon='MATERIAL') layout.operator("gp.clean_material_stack", text='Clean material Stack', icon='NODE_MATERIAL') layout.separator() layout.operator("wm.call_panel", text="Pop Palette Linker", icon='COLOR').name = "GPTB_PT_palettes_list_popup" layout.operator("gp.load_blend_palette", text='Load Mats From Single Blend', icon='RESTRICT_COLOR_ON').filepath = prefs.palette_path layout.separator() layout.operator("gp.load_palette", text='Load json Palette', icon='IMPORT').filepath = prefs.palette_path layout.operator("gp.save_palette", text='Save json Palette', icon='EXPORT').filepath = prefs.palette_path layout.separator() layout.operator("gp.move_material_to_layer", text='Move Material To Layer', icon='MATERIAL') def expose_use_channel_color_pref(self, context): # add in GreasePencilLayerDisplayPanel (gp dopesheet View > Display) layout = self.layout layout.use_property_split = True layout.use_property_decorate = False layout.label(text='Use Channel Colors (User preferences):') layout.prop(context.preferences.edit, 'use_anim_channel_group_colors') #--- Palette Linker Panels def palettes_path_ui(self, context): layout = self.layout scn = bpy.context.scene pl_prop = scn.bl_palettes_props col= layout.column() prefs = get_addon_prefs() ## Here put the path thing (only to use a non-library) # maybe in submenu... row = col.row() # expand_icon = 'TRIA_DOWN' if pl_prop.show_path else 'TRIA_RIGHT' # row.prop(pl_prop, 'show_path', text='', icon=expand_icon, emboss=False) row.prop(pl_prop, 'use_project_path', text='Use Project Palettes') # row.operator("gp.palettes_reload_blends", icon="FILE_REFRESH", text="") if pl_prop.use_project_path: ## gp toolbox addon prefs path if not prefs.palette_path: col.label(text='GP toolbox Palette Directory Needed', icon='INFO') col.operator('gptb.open_addon_prefs', icon='PREFERENCES') # if not prefs.palette_path: # or pl_prop.show_path # col.prop(prefs, 'palette_path', text='Project Dir') #col.label(text='(saved with preferences)') else: ## local path if not pl_prop.custom_dir: col.label(text='Need to specify directory') col.prop(pl_prop, 'custom_dir', text='Custom Dir') # if not pl_prop.custom_dir or pl_prop.show_path: # col.prop(pl_prop, 'custom_dir', text='Custom Dir') # col.operator('gptb.palette_version_update', text='Update Palette Version') # when update is ready def palettes_lists_ui(self, context, popup=False): layout = self.layout scn = bpy.context.scene pl_prop = scn.bl_palettes_props col= layout.column() row=col.row() # refresh button txt = 'Project Palettes' if pl_prop.use_project_path else 'Custom Palettes' row.label(text=txt) row.operator("gp.palettes_reload_blends", icon="FILE_REFRESH", text="") col= layout.column() row = col.row() if popup: blends_minimum_row = 5 objects_minimum_row = 25 else: blends_minimum_row = 2 objects_minimum_row = 4 row.template_list("GPTB_UL_blend_list", "", pl_prop, "blends", pl_prop, "bl_idx", rows=blends_minimum_row) # side panel # subcol = row.column(align=True) # subcol.operator("gp.palettes_reload_blends", icon="FILE_REFRESH", text="") ## Show object UI list only once blend Uilist is filled ? if not len(pl_prop.blends) or (len(pl_prop.blends) == 1 and not bool(pl_prop.blends[0].blend_path)): col.label(text='Select blend refresh available objects') row = col.row() row.template_list("GPTB_UL_object_list", "", pl_prop, "objects", pl_prop, "ob_idx", rows=objects_minimum_row) ## Show link button in the border of the UI list ? # col.prop(pl_prop, 'import_type') split = col.split(align=True, factor=0.4) split.prop(pl_prop, 'import_type', text='') split.enabled = len(pl_prop.objects) and bool(pl_prop.objects[pl_prop.ob_idx].path) split.operator('gp.import_obj_palette', text='Palette') # button to launch link with combined props (active only if the two items are valids) # str(Path(self.blends) / 'Object' / self.objects class GPTB_PT_palettes_linker_main_ui(Panel): bl_space_type = 'TOPBAR' # dummy bl_region_type = 'HEADER' # bl_space_type = "VIEW_3D" # bl_region_type = "UI" # bl_category = "Gpencil" bl_label = "Palettes Mat Linker" def draw(self, context): layout = self.layout ## link button for tests # layout.operator('gp.import_obj_palette', text='Palette') # Subpanel are appended to this main UI ## Or just as One fat panel # palettes_path_ui(self, context) # palettes_lists_ui(self, context) class GPTB_PT_palettes_path_ui(Panel): bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Gpencil" bl_label = "Palettes Source" # Source Path # bl_parent_id = "GPTB_PT_palettes_linker_main_ui" bl_parent_id = "GPTB_PT_color" bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout palettes_path_ui(self, context) # layout.label() # pop-up version of object lists class GPTB_PT_palettes_list_popup(Panel): bl_space_type = 'TOPBAR' # dummy bl_region_type = 'HEADER' bl_category = "Gpencil" bl_label = "Palettes Lists" bl_ui_units_x = 18 def draw(self, context): palettes_lists_ui(self, context, popup=True) class GPTB_PT_palettes_list_ui(Panel): bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Gpencil" bl_label = "Palettes Lists" bl_parent_id = "GPTB_PT_color" bl_options = {'DEFAULT_CLOSED'} def draw_header(self, context): layout = self.layout # layout.label(text="My Select Panel") layout.operator("wm.call_panel", text="", icon='COLOR').name = "GPTB_PT_palettes_list_popup" def draw(self, context): palettes_lists_ui(self, context, popup=False) ## bl 3+ UI def asset_browser_ui(self, context): '''Only shows in blender >= 3.0.0''' layout = self.layout asset_file_handle = context.asset_file_handle if asset_file_handle is None: # layout.label(text="No asset selected", icon='INFO') layout.label(text='No object/material selected', icon='INFO') return if asset_file_handle.id_type not in ('OBJECT', 'MATERIAL'): layout.label(text='No object/material selected', icon='INFO') return layout.use_property_split = True layout.use_property_decorate = False asset_library_ref = context.asset_library_ref ## Path to blend asset_lib_path = bpy.types.AssetHandle.get_full_library_path(asset_file_handle, asset_library_ref) path_to_obj = Path(asset_lib_path) / 'Objects' / asset_file_handle.name ## respect header choice ? ## import_type in (LINK, APPEND, APPEND_REUSE) imp_type = context.space_data.params.import_type if imp_type == 'APPEND': imp_txt = 'Append' elif imp_type == 'APPEND_REUSE': imp_txt = 'Append (Reuse)' else: imp_txt = 'Link' if asset_file_handle.id_type == 'MATERIAL': layout.label(text=f'From Mat: {asset_file_handle.name}') if asset_file_handle.id_type == 'OBJECT': layout.label(text=f'From Obj: {asset_file_handle.name}') layout.label(text=f'{imp_txt} Materials To GP Object') layout.operator('gp.palette_linker', text=f'{imp_txt} Materials To GP Object') ## ops # layout.label(text='Link Materials to GP Object') # Put back pop-over UI for Grease Pencil stroke interpolation tools native pop hover panel from 2.92 class GPTB_PT_tools_grease_pencil_interpolate(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'HEADER' bl_label = "Interpolate" @classmethod def poll(cls, context): if context.gpencil_data is None: return False gpd = context.gpencil_data valid_mode = bool(gpd.use_stroke_edit_mode or gpd.is_stroke_paint_mode) return bool(context.editable_gpencil_strokes) and valid_mode def draw(self, context): layout = self.layout layout.use_property_split = True # settings = context.tool_settings.gpencil_interpolate # old 2.92 global settings ## access active tool settings # settings = context.workspace.tools[0].operator_properties('gpencil.interpolate') settings = context.workspace.tools.from_space_view3d_mode('PAINT_GREASE_PENCIL').operator_properties('gpencil.interpolate') ## custom curve access (still in gp interpolate tools) interpolate_settings = context.tool_settings.gpencil_interpolate # ex : interpolate_settings.interpolation_curve.curves[0].points[1].location col = layout.column(align=True) col.label(text="Interpolate Strokes") col.operator("gpencil.interpolate", text="Interpolate") col.operator("gpencil.interpolate_sequence", text="Sequence") col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns") col = layout.column(align=True) col.label(text="Options:") # col.prop(settings, "interpolate_all_layers") # now the enum "layers" gpd = context.gpencil_data if gpd.use_stroke_edit_mode: col.prop(settings, "interpolate_selected_only") col.prop(settings, "layers") col.prop(settings, "flip") col.prop(settings, "smooth_factor") col.prop(settings, "smooth_steps") '''## Sequence Options seq_settings = context.window_manager.operators.get('GPENCIL_OT_interpolate_sequence') col = layout.column(align=True) col.label(text="Sequence Options:") if not seq_settings: # col.label(text='Launch Interpolate Sequence Once') # col.operator('gpencil.interpolate_sequence',text='Interpolate Sequence Once') col.label(text='Interpolate sequence', icon='INFO') col.label(text='must be launched') col.label(text="once per session") col.label(text="to expose it's properties") return col.prop(seq_settings, "step") col.prop(seq_settings, "layers") col.prop(seq_settings, "interpolate_selected_only") col.prop(seq_settings, "flip") col.prop(seq_settings, "smooth_factor") col.prop(seq_settings, "smooth_steps") col.prop(seq_settings, "type") if seq_settings.type == 'CUSTOM': # TODO: Options for loading/saving curve presets? col.template_curve_mapping(interpolate_settings, "interpolation_curve", brush=True, use_negative_slope=True) elif seq_settings.type != 'LINEAR': col.prop(seq_settings, "easing") if seq_settings.type == 'BACK': layout.prop(seq_settings, "back") elif seq_settings.type == 'ELASTIC': sub = layout.column(align=True) sub.prop(seq_settings, "amplitude") sub.prop(seq_settings, "period") ''' ## recreate property group from operator options # inspect context.window_manager.operators['GPENCIL_OT_interpolate_sequence'] # separate options from single interpolation and sequence interpolation # class GPTB_PG_interpolate_sequence_prop(bpy.types.PropertyGroup): # interpolate_selected_only : BoolProperty( # name="Selected Only", # description="", # default=True, # options={'HIDDEN'}) def interpolate_header_ui(self, context): layout = self.layout obj = context.active_object if obj and obj.type == 'GREASEPENCIL' and context.gpencil_data: gpd = context.gpencil_data else: return if gpd.use_stroke_edit_mode or gpd.is_stroke_paint_mode: row = layout.row(align=True) row.popover( panel="GPTB_PT_tools_grease_pencil_interpolate", text="Interpolate", ) classes = ( GPTB_PT_sidebar_panel, GPTB_PT_checker, GPTB_PT_anim_manager, GPTB_PT_color, GPTB_PT_tint_layers, GPTB_PT_toolbox_playblast, # GPTB_PT_tools_grease_pencil_interpolate, # WIP # palettes linker GPTB_PT_palettes_linker_main_ui, # main panel GPTB_PT_palettes_list_popup, # popup (dummy region) GPTB_PT_palettes_path_ui, # subpanels GPTB_PT_palettes_list_ui, # subpanels # GPTB_PT_extra, ) def register(): for cls in classes: bpy.utils.register_class(cls) bpy.types.GPENCIL_MT_material_context_menu.append(palette_manager_menu) bpy.types.DOPESHEET_PT_grease_pencil_mode.append(expose_use_channel_color_pref) # bpy.types.GPENCIL_MT_material_context_menu.append(palette_manager_menu) # bpy.types.DOPESHEET_PT_gpencil_layer_display.append(expose_use_channel_color_pref) # bpy.types.VIEW3D_HT_header.append(interpolate_header_ui) # WIP # if bpy.app.version >= (3,0,0): # bpy.types.ASSETBROWSER_PT_metadata.append(asset_browser_ui) def unregister(): # bpy.types.VIEW3D_HT_header.remove(interpolate_header_ui) # WIP bpy.types.DOPESHEET_PT_grease_pencil_mode.remove(expose_use_channel_color_pref) bpy.types.GPENCIL_MT_material_context_menu.remove(palette_manager_menu) # bpy.types.DOPESHEET_PT_gpencil_layer_display.remove(expose_use_channel_color_pref) # bpy.types.GPENCIL_MT_material_context_menu.remove(palette_manager_menu) # if bpy.app.version >= (3,0,0): # bpy.types.ASSETBROWSER_PT_metadata.remove(asset_browser_ui) for cls in reversed(classes): bpy.utils.unregister_class(cls) """ ## direct panel def append (no submenu with arrow) ## need to use append and remove in register/unregister # bpy.types.DATA_PT_gpencil_layers.append(UI_tools.GPdata_toolbox_panel) # bpy.types.DATA_PT_gpencil_layers.remove(UI_tools.GPdata_toolbox_panel) def GPdata_toolbox_panel(self, context): layout = self.layout layout.use_property_split = True settings = context.scene.gptoolprops col = layout.column(align = True) col.prop(settings, 'autotint_offset') col.operator("gp.auto_tint_gp_layers", icon = "COLOR").reset = False col.operator("gp.auto_tint_gp_layers", text = "Reset tint", icon = "COLOR").reset = True """