492 lines
17 KiB
Python
492 lines
17 KiB
Python
# This program is free software; you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation; either version 3 of the License, or
|
||
# (at your option) any later version.
|
||
#
|
||
# This program is distributed in the hope that it will be useful, but
|
||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
# General Public License for more details.
|
||
#
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
bl_info = {
|
||
"name": "GP toolbox",
|
||
"description": "Set of tools for Grease Pencil in animation production",
|
||
"author": "Samuel Bernou",
|
||
"version": (1, 3, 1),
|
||
"blender": (2, 91, 0),
|
||
"location": "sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
|
||
"warning": "",
|
||
"doc_url": "https://gitlab.com/autour-de-minuit/blender/gp_toolbox",
|
||
"tracker_url": "https://gitlab.com/autour-de-minuit/blender/gp_toolbox/-/issues",
|
||
"category": "3D View",
|
||
}
|
||
|
||
from . import addon_updater_ops
|
||
|
||
from .utils import *
|
||
from .functions import *
|
||
|
||
## GMIC
|
||
from .GP_guided_colorize import GP_colorize
|
||
|
||
## direct tools
|
||
from . import OP_breakdowner
|
||
from . import OP_temp_cutter
|
||
from . import OP_playblast_bg
|
||
from . import OP_playblast
|
||
from . import OP_helpers
|
||
from . import OP_keyframe_jump
|
||
from . import OP_cursor_snap_canvas
|
||
from . import OP_palettes
|
||
from . import OP_file_checker
|
||
from . import OP_render
|
||
from . import OP_copy_paste
|
||
from . import OP_realign
|
||
from . import OP_depth_move
|
||
from . import OP_key_duplicate_send
|
||
from . import keymaps
|
||
|
||
from .OP_pseudo_tint import GPT_OT_auto_tint_gp_layers
|
||
|
||
from . import UI_tools
|
||
|
||
from .properties import GP_PG_ToolsSettings
|
||
|
||
from bpy.props import (FloatProperty,
|
||
BoolProperty,
|
||
EnumProperty,
|
||
StringProperty,
|
||
IntProperty)
|
||
|
||
import bpy
|
||
from bpy.app.handlers import persistent
|
||
from pathlib import Path
|
||
# from .eyedrop import EyeDropper
|
||
# from .properties import load_icons,remove_icons
|
||
|
||
|
||
### prefs
|
||
# def set_palette_path(self, context):
|
||
# print('value set')
|
||
# self.palette_path = Path(bpy.path.abspath(self["palette_path"])).as_posix()
|
||
|
||
|
||
@persistent
|
||
def remap_relative(dummy):
|
||
# try:
|
||
all_path = [lib for lib in bpy.utils.blend_paths(local=True)]
|
||
bpy.ops.file.make_paths_relative()
|
||
for i, lib in enumerate(bpy.utils.blend_paths(local=True)):
|
||
if all_path[i] != lib:
|
||
print('Remapped:', all_path[i], '\n>> ', lib)
|
||
# except Exception as e:
|
||
# print(e)
|
||
|
||
def remap_on_save_update(self, context):
|
||
pref = get_addon_prefs()
|
||
if pref.use_relative_remap_on_save:
|
||
if not 'remap_relative' in [hand.__name__ for hand in bpy.app.handlers.save_pre]:
|
||
bpy.app.handlers.save_pre.append(remap_relative)
|
||
|
||
else:
|
||
if 'remap_relative' in [hand.__name__ for hand in bpy.app.handlers.save_pre]:
|
||
bpy.app.handlers.save_pre.remove(remap_relative)
|
||
|
||
class GPTB_prefs(bpy.types.AddonPreferences):
|
||
bl_idname = __name__
|
||
|
||
## tabs
|
||
|
||
pref_tabs : EnumProperty(
|
||
items=(('PREF', "Preferences", "Change some preferences of the modal"),
|
||
('MAN_OPS', "Operator", "Operator to add Manually"),
|
||
# ('TUTO', "Tutorial", "How to use the tool"),
|
||
('UPDATE', "Update", "Check and apply updates"),
|
||
# ('KEYMAP', "Keymap", "customise the default keymap"),
|
||
),
|
||
default='PREF')
|
||
|
||
## addon pref updater props
|
||
|
||
auto_check_update : BoolProperty(
|
||
name="Auto-check for Update",
|
||
description="If enabled, auto-check for updates using an interval",
|
||
default=False,
|
||
)
|
||
|
||
updater_intrval_months : IntProperty(
|
||
name='Months',
|
||
description="Number of months between checking for updates",
|
||
default=0,
|
||
min=0
|
||
)
|
||
updater_intrval_days : IntProperty(
|
||
name='Days',
|
||
description="Number of days between checking for updates",
|
||
default=7,
|
||
min=0,
|
||
max=31
|
||
)
|
||
updater_intrval_hours : IntProperty(
|
||
name='Hours',
|
||
description="Number of hours between checking for updates",
|
||
default=0,
|
||
min=0,
|
||
max=23
|
||
)
|
||
updater_intrval_minutes : IntProperty(
|
||
name='Minutes',
|
||
description="Number of minutes between checking for updates",
|
||
default=0,
|
||
min=0,
|
||
max=59
|
||
)
|
||
|
||
## addon prefs
|
||
|
||
## Project preferences
|
||
# subtype (string) – Enumerator in ['FILE_PATH', 'DIR_PATH', 'FILE_NAME', 'BYTE_STRING', 'PASSWORD', 'NONE'].
|
||
|
||
## fps
|
||
|
||
use_relative_remap_on_save : BoolProperty(
|
||
name="Relative Remap On Save",
|
||
description="Always remap all external path to relative when saving\nNeed blender restart if changed",
|
||
default=False,
|
||
update=remap_on_save_update
|
||
)
|
||
|
||
fps : IntProperty(
|
||
name='Frame Rate',
|
||
description="Fps of the project, Used to conform the file when you use Check file operator",
|
||
default=25,
|
||
min=1,
|
||
max=10000
|
||
)
|
||
|
||
## output settings for automated renders
|
||
output_parent_level = IntProperty(
|
||
name='Parent level',
|
||
description="Go up in folder to define a render path relative to the file in upper directotys",
|
||
default=0,
|
||
min=0,
|
||
max=20
|
||
)
|
||
|
||
output_path : StringProperty(
|
||
name="Output path",
|
||
description="Path relative to blend to place render",
|
||
default="//render", maxlen=0, subtype='DIR_PATH')
|
||
|
||
separator : StringProperty(
|
||
name="Namespace separator",
|
||
description="Character delimiter to use for detecting namespace (prefix), default is '_', space if nothing specified",
|
||
default="_", maxlen=0, subtype='NONE')
|
||
|
||
palette_path : StringProperty(
|
||
name="Palettes directory",
|
||
description="Path to palette containing palette.json files to save and load",
|
||
default="//", maxlen=0, subtype='DIR_PATH')#, update = set_palette_path
|
||
|
||
## Playblast prefs
|
||
playblast_auto_play : BoolProperty(
|
||
name="Playblast auto play",
|
||
description="Open rendered playblast when finished",
|
||
default=True,
|
||
)
|
||
|
||
playblast_auto_open_folder : BoolProperty(
|
||
name="Playblast auto open location",
|
||
description="Open folder of rendered playblast when finished",
|
||
default=False,
|
||
)
|
||
|
||
## default active tool to use
|
||
select_active_tool : EnumProperty(
|
||
name="Default selection tool", description="Active tool to set when launching check fix scene",
|
||
default='builtin.select_lasso',
|
||
items=(
|
||
('none', 'Dont change', 'Let the current active tool without change', 0),#'MOUSE_RMB'
|
||
('builtin.select', 'Select tweak', 'Use active select tweak active tool', 1),#'MOUSE_RMB'
|
||
('builtin.select_box', 'Select box', 'Use active select box active tool', 2),#'MOUSE_LMB'
|
||
('builtin.select_circle', 'Select circle', 'Use active select circle active tool', 3),#'MOUSE_MMB'
|
||
('builtin.select_lasso', 'Select lasso', 'Use active select lasso active tool', 4),#'MOUSE_MMB'
|
||
))
|
||
|
||
|
||
## render settings
|
||
render_obj_exclusion : StringProperty(
|
||
name="GP obj exclude filter",
|
||
description="List comma separated words to exclude from render list",
|
||
default="old,rough,trash,test")#, subtype='FILE_PATH')
|
||
|
||
render_res_x : IntProperty(
|
||
name='Resolution X',
|
||
description="Resolution on X",
|
||
default=2048,
|
||
min=1,
|
||
max=10000
|
||
)
|
||
render_res_y : IntProperty(
|
||
name='Resolution Y',
|
||
description="Resolution on Y",
|
||
default=1080,
|
||
min=1,
|
||
max=10000
|
||
)
|
||
|
||
## KF jumper
|
||
kfj_use_shortcut: BoolProperty(
|
||
name = "Use Keyframe Jump Shortcut",
|
||
description = "Auto bind shotcut for keyframe jump (else you can bind manually using 'screen.gp_keyframe_jump' id_name)",
|
||
default = True)
|
||
|
||
kfj_prev_keycode : StringProperty(
|
||
name="Jump Prev Shortcut",
|
||
description="Shortcut to trigger previous keyframe jump",
|
||
default="F5")
|
||
|
||
kfj_prev_shift: BoolProperty(
|
||
name = "Shift",
|
||
description = "add shift",
|
||
default = False)
|
||
|
||
kfj_prev_alt: BoolProperty(
|
||
name = "Alt",
|
||
description = "add alt",
|
||
default = False)
|
||
|
||
kfj_prev_ctrl: BoolProperty(
|
||
name = "combine with ctrl",
|
||
description = "add ctrl",
|
||
default = False)
|
||
|
||
kfj_next_keycode : StringProperty(
|
||
name="Jump Next Shortcut",
|
||
description="Shortcut to trigger keyframe jump",
|
||
default="F6")
|
||
|
||
kfj_next_shift: BoolProperty(
|
||
name = "Shift",
|
||
description = "add shift",
|
||
default = False)
|
||
|
||
kfj_next_alt: BoolProperty(
|
||
name = "Alt",
|
||
description = "add alt",
|
||
default = False)
|
||
|
||
kfj_next_ctrl: BoolProperty(
|
||
name = "combine with ctrl",
|
||
description = "add ctrl",
|
||
default = False)
|
||
|
||
## Temp cutter
|
||
# temp_cutter_use_shortcut: BoolProperty(
|
||
# name = "Use temp cutter Shortcut",
|
||
# description = "Auto assign shortcut for temp_cutter",
|
||
# default = True)
|
||
|
||
def draw(self, context):
|
||
layout = self.layout## random color
|
||
# layout.use_property_split = True
|
||
|
||
row= layout.row(align=True)
|
||
row.prop(self, "pref_tabs", expand=True)
|
||
|
||
|
||
if self.pref_tabs == 'PREF':
|
||
box = layout.box()
|
||
box.label(text='Project settings')
|
||
|
||
## Render
|
||
# box.label(text='Render option:')
|
||
box.prop(self, 'fps')
|
||
row = box.row(align = True)
|
||
row.label(text='Render Resolution')
|
||
row.prop(self, 'render_res_x', text='Width')
|
||
row.prop(self, 'render_res_y', text='Height')
|
||
## Palette
|
||
box.label(text='Palette library folder:')
|
||
box.prop(self, 'palette_path')
|
||
|
||
## render output
|
||
box.prop(self, 'output_path')
|
||
box.prop(self, 'use_relative_remap_on_save')
|
||
|
||
### TODO add render settings
|
||
|
||
# layout.separator()## Playblast
|
||
box = layout.box()
|
||
box.label(text='Playblast options:')
|
||
box.prop(self, 'playblast_auto_play')
|
||
box.prop(self, 'playblast_auto_open_folder')
|
||
|
||
# box.separator()## Keyframe jumper
|
||
box = layout.box()
|
||
box.label(text='Keyframe Jump option:')
|
||
|
||
box.prop(self, "kfj_use_shortcut", text='Bind shortcuts')
|
||
if self.kfj_use_shortcut:
|
||
prompt = '[TYPE SHORTCUT TO USE (can be with modifiers)]'
|
||
if self.kfj_prev_keycode:
|
||
mods = '+'.join([m for m, b in [('Ctrl', self.kfj_prev_ctrl), ('Shift', self.kfj_prev_shift), ('Alt', self.kfj_prev_alt)] if b])
|
||
text = f'{mods}+{self.kfj_prev_keycode}' if mods else self.kfj_prev_keycode
|
||
text = f'Jump Keyframe Prev: {text} (Click to change)'
|
||
else:
|
||
text = prompt
|
||
ops = box.operator('prefs.shortcut_rebinder', text=text, icon='FILE_REFRESH')
|
||
ops.s_keycode = 'kfj_prev_keycode'
|
||
ops.s_ctrl = 'kfj_prev_ctrl'
|
||
ops.s_shift = 'kfj_prev_shift'
|
||
ops.s_alt = 'kfj_prev_alt'
|
||
|
||
if self.kfj_next_keycode:
|
||
mods = '+'.join([m for m, b in [('Ctrl', self.kfj_next_ctrl), ('Shift', self.kfj_next_shift), ('Alt', self.kfj_next_alt)] if b])
|
||
text = f'{mods}+{self.kfj_next_keycode}' if mods else self.kfj_next_keycode
|
||
text = f'Jump Keyframe Next: {text} (Click to change)'
|
||
else:
|
||
text = prompt
|
||
ops = box.operator('prefs.shortcut_rebinder', text=text, icon='FILE_REFRESH')
|
||
ops.s_keycode = 'kfj_next_keycode'
|
||
ops.s_ctrl = 'kfj_next_ctrl'
|
||
ops.s_shift = 'kfj_next_shift'
|
||
ops.s_alt = 'kfj_next_alt'
|
||
|
||
else:
|
||
box.label(text="No Jump hotkey auto set. Following operators needs to be set manually", icon="ERROR")
|
||
box.label(text="screen.gp_keyframe_jump - preferably in 'screen' category to jump from any editor")
|
||
|
||
## Active tool
|
||
box = layout.box()
|
||
box.label(text='Autofix check button options:')
|
||
box.prop(self, "select_active_tool", icon='RESTRICT_SELECT_OFF')
|
||
|
||
|
||
box.prop(self, "render_obj_exclusion", icon='FILTER')#
|
||
|
||
## random color character separator
|
||
box = layout.box()
|
||
box.label(text='Random color options:')
|
||
box.prop(self, 'separator')
|
||
|
||
|
||
if self.pref_tabs == 'MAN_OPS':
|
||
# layout.separator()## notes
|
||
# layout.label(text='Notes:')
|
||
layout.label(text='Following operators ID have to be set manually in keymap if needed :')
|
||
|
||
## keyframe jump
|
||
box = layout.box()
|
||
box.label(text='GP keyframe jump (consider only GP keyframe, multiple options available at setup)')
|
||
row = box.row()
|
||
row.label(text='screen.gp_keyframe_jump')
|
||
row.operator('wm.copytext', icon='COPYDOWN').text = 'screen.gp_keyframe_jump'
|
||
|
||
# layout.separator()
|
||
## Snap cursor to GP
|
||
box = layout.box()
|
||
box.label(text='Snap cursor to GP canvas (if not autoset)')
|
||
row = box.row()
|
||
row.label(text='Look for default 3d snap operators by searching "view3d.cursor3d"')
|
||
row.operator('wm.copytext', text='Copy "view3d.cursor3d"', icon='COPYDOWN').text = 'view3d.cursor3d'
|
||
row = box.row()
|
||
row.label(text='Replace wanted by "view3d.cusor_snap"')
|
||
row.operator('wm.copytext', text='Copy "view3d.cusor_snap"', icon='COPYDOWN').text = 'view3d.cusor_snap'
|
||
box.label(text='Or just create a new shortcut using cursor_snap')
|
||
|
||
## Clear keyframe
|
||
box = layout.box()
|
||
box.label(text='Clear active frame (delete all strokes without deleting the frame)')
|
||
row = box.row()
|
||
row.label(text='gp.clear_active_frame')
|
||
row.operator('wm.copytext', icon='COPYDOWN').text = 'gp.clear_active_frame'
|
||
|
||
## user prefs
|
||
box = layout.box()
|
||
box.label(text='Note: You can access user pref file and startup file in config folder')
|
||
box.operator("wm.path_open", text='Open config location').filepath = bpy.utils.user_resource('CONFIG')
|
||
|
||
if self.pref_tabs == 'UPDATE':
|
||
addon_updater_ops.update_settings_ui(self, context)
|
||
|
||
|
||
### --- REGISTER ---
|
||
|
||
# class GP_PG_ToolsSettings(bpy.types.PropertyGroup) :
|
||
# autotint_offset = bpy.props.IntProperty(name="Tint hue offset", description="offset the tint by this value for better color", default=0, min=-5000, max=5000, soft_min=-999, soft_max=999, step=1)#, subtype='PERCENTAGE'
|
||
|
||
|
||
classes = (
|
||
GPTB_prefs,
|
||
GP_PG_ToolsSettings,
|
||
GPT_OT_auto_tint_gp_layers,
|
||
)
|
||
|
||
# register, unregister = bpy.utils.register_classes_factory(classes)
|
||
|
||
|
||
def register():
|
||
addon_updater_ops.register(bl_info)
|
||
for cls in classes:
|
||
bpy.utils.register_class(cls)
|
||
OP_helpers.register()
|
||
OP_keyframe_jump.register()
|
||
OP_file_checker.register()
|
||
OP_breakdowner.register()
|
||
OP_temp_cutter.register()
|
||
GP_colorize.register()## GP_guided_colorize.
|
||
OP_playblast_bg.register()
|
||
OP_playblast.register()
|
||
OP_palettes.register()
|
||
OP_cursor_snap_canvas.register()
|
||
OP_render.register()
|
||
OP_copy_paste.register()
|
||
OP_realign.register()
|
||
OP_depth_move.register()
|
||
OP_key_duplicate_send.register()
|
||
UI_tools.register()
|
||
keymaps.register()
|
||
bpy.types.Scene.gptoolprops = bpy.props.PointerProperty(type = GP_PG_ToolsSettings)
|
||
|
||
# add handler (if option is on)
|
||
|
||
if get_addon_prefs().use_relative_remap_on_save:
|
||
if not 'remap_relative' in [hand.__name__ for hand in bpy.app.handlers.save_pre]:
|
||
bpy.app.handlers.save_pre.append(remap_relative)
|
||
|
||
|
||
def unregister():
|
||
# remove handler
|
||
if 'remap_relative' in [hand.__name__ for hand in bpy.app.handlers.save_pre]:
|
||
bpy.app.handlers.save_pre.remove(remap_relative)
|
||
|
||
keymaps.unregister()
|
||
addon_updater_ops.unregister()
|
||
for cls in reversed(classes):
|
||
bpy.utils.unregister_class(cls)
|
||
UI_tools.unregister()
|
||
OP_key_duplicate_send.unregister()
|
||
OP_depth_move.unregister()
|
||
OP_realign.unregister()
|
||
OP_copy_paste.unregister()
|
||
OP_render.unregister()
|
||
OP_cursor_snap_canvas.unregister()
|
||
OP_palettes.unregister()
|
||
OP_file_checker.unregister()
|
||
OP_helpers.unregister()
|
||
OP_keyframe_jump.unregister()
|
||
OP_breakdowner.unregister()
|
||
OP_temp_cutter.unregister()
|
||
GP_colorize.unregister()## GP_guided_colorize.
|
||
OP_playblast_bg.unregister()
|
||
OP_playblast.unregister()
|
||
del bpy.types.Scene.gptoolprops
|
||
|
||
|
||
if __name__ == "__main__":
|
||
register()
|