Native addon compatibility
1.0.0: - Compatible with official grease pencil tools - removed box deform and rotate canvas that existed in othergpv2
parent
6774484226
commit
fdbfaaa1e0
579
OP_box_deform.py
579
OP_box_deform.py
|
@ -1,579 +0,0 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
'''
|
||||
Based on Box_deform addon
|
||||
! Standalone file ! Stripped preference, and set best default auto transform)
|
||||
'''
|
||||
|
||||
|
||||
import bpy
|
||||
import numpy as np
|
||||
|
||||
""" def get_addon_prefs():
|
||||
import os
|
||||
addon_name = os.path.splitext(__name__)[0]
|
||||
preferences = bpy.context.preferences
|
||||
addon_prefs = preferences.addons[addon_name].preferences
|
||||
return (addon_prefs) """
|
||||
|
||||
def location_to_region(worldcoords):
|
||||
from bpy_extras import view3d_utils
|
||||
return view3d_utils.location_3d_to_region_2d(bpy.context.region, bpy.context.space_data.region_3d, worldcoords)
|
||||
|
||||
def region_to_location(viewcoords, depthcoords):
|
||||
from bpy_extras import view3d_utils
|
||||
return view3d_utils.region_2d_to_location_3d(bpy.context.region, bpy.context.space_data.region_3d, viewcoords, depthcoords)
|
||||
|
||||
def assign_vg(obj, vg_name):
|
||||
## create vertex group
|
||||
vg = obj.vertex_groups.get(vg_name)
|
||||
if vg:
|
||||
# remove to start clean
|
||||
obj.vertex_groups.remove(vg)
|
||||
vg = obj.vertex_groups.new(name=vg_name)
|
||||
bpy.ops.gpencil.vertex_group_assign()
|
||||
return vg
|
||||
|
||||
def view_cage(obj):
|
||||
|
||||
lattice_interp = 'KEY_LINEAR'#get_addon_prefs().default_deform_type
|
||||
|
||||
gp = obj.data
|
||||
gpl = gp.layers
|
||||
|
||||
coords = []
|
||||
initial_mode = bpy.context.mode
|
||||
|
||||
## get points
|
||||
if bpy.context.mode == 'EDIT_GPENCIL':
|
||||
for l in gpl:
|
||||
if l.lock or l.hide or not l.active_frame:#or len(l.frames)
|
||||
continue
|
||||
if gp.use_multiedit:
|
||||
target_frames = [f for f in l.frames if f.select]
|
||||
else:
|
||||
target_frames = [l.active_frame]
|
||||
|
||||
for f in target_frames:
|
||||
for s in f.strokes:
|
||||
if not s.select:
|
||||
continue
|
||||
for p in s.points:
|
||||
if p.select:
|
||||
# get real location
|
||||
coords.append(obj.matrix_world @ p.co)
|
||||
|
||||
elif bpy.context.mode == 'OBJECT':#object mode -> all points
|
||||
for l in gpl:# if l.hide:continue# only visible ? (might break things)
|
||||
if not len(l.frames):
|
||||
continue#skip frameless layer
|
||||
for s in l.active_frame.strokes:
|
||||
for p in s.points:
|
||||
coords.append(obj.matrix_world @ p.co)
|
||||
|
||||
elif bpy.context.mode == 'PAINT_GPENCIL':
|
||||
# get last stroke points coordinated
|
||||
if not gpl.active or not gpl.active.active_frame:
|
||||
return 'No frame to deform'
|
||||
|
||||
if not len(gpl.active.active_frame.strokes):
|
||||
return 'No stroke found to deform'
|
||||
|
||||
paint_id = -1
|
||||
if bpy.context.scene.tool_settings.use_gpencil_draw_onback:
|
||||
paint_id = 0
|
||||
coords = [obj.matrix_world @ p.co for p in gpl.active.active_frame.strokes[paint_id].points]
|
||||
|
||||
else:
|
||||
return 'Wrong mode!'
|
||||
|
||||
if not coords:
|
||||
## maybe silent return instead (need special str code to manage errorless return)
|
||||
return 'No points found!'
|
||||
|
||||
if bpy.context.mode in ('EDIT_GPENCIL', 'PAINT_GPENCIL') and len(coords) < 2:
|
||||
# Dont block object mod
|
||||
return 'Less than two point selected'
|
||||
|
||||
vg_name = 'lattice_cage_deform_group'
|
||||
|
||||
if bpy.context.mode == 'EDIT_GPENCIL':
|
||||
vg = assign_vg(obj, vg_name)
|
||||
|
||||
if bpy.context.mode == 'PAINT_GPENCIL':
|
||||
# points cannot be assign to API yet(ugly and slow workaround but only way)
|
||||
# -> https://developer.blender.org/T56280 so, hop'in'ops !
|
||||
|
||||
# store selection and deselect all
|
||||
plist = []
|
||||
for s in gpl.active.active_frame.strokes:
|
||||
for p in s.points:
|
||||
plist.append([p, p.select])
|
||||
p.select = False
|
||||
|
||||
# select
|
||||
## foreach_set does not update
|
||||
# gpl.active.active_frame.strokes[paint_id].points.foreach_set('select', [True]*len(gpl.active.active_frame.strokes[paint_id].points))
|
||||
for p in gpl.active.active_frame.strokes[paint_id].points:
|
||||
p.select = True
|
||||
|
||||
# assign
|
||||
bpy.ops.object.mode_set(mode='EDIT_GPENCIL')
|
||||
vg = assign_vg(obj, vg_name)
|
||||
|
||||
# restore
|
||||
for pl in plist:
|
||||
pl[0].select = pl[1]
|
||||
|
||||
|
||||
## View axis Mode ---
|
||||
|
||||
## get view coordinate of all points
|
||||
coords2D = [location_to_region(co) for co in coords]
|
||||
|
||||
# find centroid for depth (or more economic, use obj origin...)
|
||||
centroid = np.mean(coords, axis=0)
|
||||
|
||||
# not a mean ! a mean of extreme ! centroid2d = np.mean(coords2D, axis=0)
|
||||
all_x, all_y = np.array(coords2D)[:, 0], np.array(coords2D)[:, 1]
|
||||
min_x, min_y = np.min(all_x), np.min(all_y)
|
||||
max_x, max_y = np.max(all_x), np.max(all_y)
|
||||
|
||||
width = (max_x - min_x)
|
||||
height = (max_y - min_y)
|
||||
center_x = min_x + (width/2)
|
||||
center_y = min_y + (height/2)
|
||||
|
||||
centroid2d = (center_x,center_y)
|
||||
center = region_to_location(centroid2d, centroid)
|
||||
# bpy.context.scene.cursor.location = center#Dbg
|
||||
|
||||
|
||||
#corner Bottom-left to Bottom-right
|
||||
x0 = region_to_location((min_x, min_y), centroid)
|
||||
x1 = region_to_location((max_x, min_y), centroid)
|
||||
x_worldsize = (x0 - x1).length
|
||||
|
||||
#corner Bottom-left to top-left
|
||||
y0 = region_to_location((min_x, min_y), centroid)
|
||||
y1 = region_to_location((min_x, max_y), centroid)
|
||||
y_worldsize = (y0 - y1).length
|
||||
|
||||
## in case of 3
|
||||
|
||||
lattice_name = 'lattice_cage_deform'
|
||||
# cleaning
|
||||
cage = bpy.data.objects.get(lattice_name)
|
||||
if cage:
|
||||
bpy.data.objects.remove(cage)
|
||||
|
||||
lattice = bpy.data.lattices.get(lattice_name)
|
||||
if lattice:
|
||||
bpy.data.lattices.remove(lattice)
|
||||
|
||||
# create lattice object
|
||||
lattice = bpy.data.lattices.new(lattice_name)
|
||||
cage = bpy.data.objects.new(lattice_name, lattice)
|
||||
cage.show_in_front = True
|
||||
|
||||
## Master (root) collection
|
||||
bpy.context.scene.collection.objects.link(cage)
|
||||
|
||||
# spawn cage and align it to view (Again ! align something to a vector !!! argg)
|
||||
|
||||
r3d = bpy.context.space_data.region_3d
|
||||
viewmat = r3d.view_matrix
|
||||
|
||||
cage.matrix_world = viewmat.inverted()
|
||||
cage.scale = (x_worldsize, y_worldsize, 1)
|
||||
## Z aligned in view direction (need minus X 90 degree to be aligned FRONT)
|
||||
# cage.rotation_euler.x -= radians(90)
|
||||
# cage.scale = (x_worldsize, 1, y_worldsize)
|
||||
cage.location = center
|
||||
|
||||
lattice.points_u = 2
|
||||
lattice.points_v = 2
|
||||
lattice.points_w = 1
|
||||
|
||||
lattice.interpolation_type_u = lattice_interp#'KEY_LINEAR'-'KEY_BSPLINE'
|
||||
lattice.interpolation_type_v = lattice_interp#'KEY_LINEAR'-'KEY_BSPLINE'
|
||||
lattice.interpolation_type_w = lattice_interp#'KEY_LINEAR'-'KEY_BSPLINE'
|
||||
|
||||
mod = obj.grease_pencil_modifiers.new('tmp_lattice', 'GP_LATTICE')
|
||||
|
||||
# move to top if modifiers exists
|
||||
for _ in range(len(obj.grease_pencil_modifiers)):
|
||||
bpy.ops.object.gpencil_modifier_move_up(modifier='tmp_lattice')
|
||||
|
||||
mod.object = cage
|
||||
|
||||
if initial_mode == 'PAINT_GPENCIL':
|
||||
mod.layer = gpl.active.info
|
||||
|
||||
# note : if initial was Paint, changed to Edit
|
||||
# so vertex attribution is valid even for paint
|
||||
if bpy.context.mode == 'EDIT_GPENCIL':
|
||||
mod.vertex_group = vg.name
|
||||
|
||||
#Go in object mode if not already
|
||||
if bpy.context.mode != 'OBJECT':
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Store name of deformed object in case of 'revive modal'
|
||||
cage.vertex_groups.new(name=obj.name)
|
||||
|
||||
## select and make cage active
|
||||
# cage.select_set(True)
|
||||
bpy.context.view_layer.objects.active = cage
|
||||
obj.select_set(False)#deselect GP object
|
||||
bpy.ops.object.mode_set(mode='EDIT')# go in lattice edit mode
|
||||
bpy.ops.lattice.select_all(action='SELECT')# select all points
|
||||
|
||||
## Eventually change tool mode to tweak for direct point editing (reset after before leaving)
|
||||
bpy.ops.wm.tool_set_by_id(name="builtin.select")# Tweaktoolcode
|
||||
return cage
|
||||
|
||||
|
||||
def back_to_obj(obj, gp_mode, org_lattice_toolset, context):
|
||||
if context.mode == 'EDIT_LATTICE' and org_lattice_toolset:# Tweaktoolcode - restore the active tool used by lattice edit..
|
||||
bpy.ops.wm.tool_set_by_id(name = org_lattice_toolset)# Tweaktoolcode
|
||||
|
||||
# gp object active and selected
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
obj.select_set(True)
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
|
||||
|
||||
def delete_cage(cage):
|
||||
lattice = cage.data
|
||||
bpy.data.objects.remove(cage)
|
||||
bpy.data.lattices.remove(lattice)
|
||||
|
||||
def apply_cage(gp_obj, cage):
|
||||
mod = gp_obj.grease_pencil_modifiers.get('tmp_lattice')
|
||||
if mod:
|
||||
bpy.ops.object.gpencil_modifier_apply(apply_as='DATA', modifier=mod.name)
|
||||
else:
|
||||
print('tmp_lattice modifier not found to apply...')
|
||||
|
||||
delete_cage(cage)
|
||||
|
||||
def cancel_cage(gp_obj, cage):
|
||||
#remove modifier
|
||||
mod = gp_obj.grease_pencil_modifiers.get('tmp_lattice')
|
||||
if mod:
|
||||
gp_obj.grease_pencil_modifiers.remove(mod)
|
||||
else:
|
||||
print('tmp_lattice modifier not found to remove...')
|
||||
|
||||
delete_cage(cage)
|
||||
|
||||
|
||||
class GP_OT_latticeGpDeform(bpy.types.Operator):
|
||||
"""Create a lattice to use as quad corner transform"""
|
||||
bl_idname = "gp.latticedeform"
|
||||
bl_label = "Box deform"
|
||||
bl_description = "Use lattice for free box transforms on grease pencil points (Ctrl+T)"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.object is not None and context.object.type in ('GPENCIL','LATTICE')
|
||||
|
||||
# local variable
|
||||
tab_press_ct = 0
|
||||
|
||||
def modal(self, context, event):
|
||||
display_text = f"Deform Cage size: {self.lat.points_u}x{self.lat.points_v} (1-9 or ctrl + ←→↑↓]) | \
|
||||
mode (M) : {'Linear' if self.lat.interpolation_type_u == 'KEY_LINEAR' else 'Spline'} | \
|
||||
valid:Spacebar/Enter/Tab, cancel:Del/Backspace"
|
||||
context.area.header_text_set(display_text)
|
||||
|
||||
|
||||
## Handle ctrl+Z
|
||||
if event.type in {'Z'} and event.value == 'PRESS' and event.ctrl:
|
||||
## Disable (capture key)
|
||||
return {"RUNNING_MODAL"}
|
||||
## Not found how possible to find modal start point in undo stack to
|
||||
# print('ops list', context.window_manager.operators.keys())
|
||||
# if context.window_manager.operators:#can be empty
|
||||
# print('\nlast name', context.window_manager.operators[-1].name)
|
||||
|
||||
# Auto interpo check
|
||||
if self.auto_interp:
|
||||
if event.type in {'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', 'NINE', 'ZERO',} and event.value == 'PRESS':
|
||||
self.set_lattice_interp('KEY_BSPLINE')
|
||||
if event.type in {'DOWN_ARROW', "UP_ARROW", "RIGHT_ARROW", "LEFT_ARROW"} and event.value == 'PRESS' and event.ctrl:
|
||||
self.set_lattice_interp('KEY_BSPLINE')
|
||||
if event.type in {'ONE'} and event.value == 'PRESS':
|
||||
self.set_lattice_interp('KEY_LINEAR')
|
||||
|
||||
# Single keys
|
||||
if event.type in {'H'} and event.value == 'PRESS':
|
||||
# self.report({'INFO'}, "Can't hide")
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'ONE'} and event.value == 'PRESS':# , 'NUMPAD_1'
|
||||
self.lat.points_u = self.lat.points_v = 2
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'TWO'} and event.value == 'PRESS':# , 'NUMPAD_2'
|
||||
self.lat.points_u = self.lat.points_v = 3
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'THREE'} and event.value == 'PRESS':# , 'NUMPAD_3'
|
||||
self.lat.points_u = self.lat.points_v = 4
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'FOUR'} and event.value == 'PRESS':# , 'NUMPAD_4'
|
||||
self.lat.points_u = self.lat.points_v = 5
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'FIVE'} and event.value == 'PRESS':# , 'NUMPAD_5'
|
||||
self.lat.points_u = self.lat.points_v = 6
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'SIX'} and event.value == 'PRESS':# , 'NUMPAD_6'
|
||||
self.lat.points_u = self.lat.points_v = 7
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'SEVEN'} and event.value == 'PRESS':# , 'NUMPAD_7'
|
||||
self.lat.points_u = self.lat.points_v = 8
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'EIGHT'} and event.value == 'PRESS':# , 'NUMPAD_8'
|
||||
self.lat.points_u = self.lat.points_v = 9
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'NINE'} and event.value == 'PRESS':# , 'NUMPAD_9'
|
||||
self.lat.points_u = self.lat.points_v = 10
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'ZERO'} and event.value == 'PRESS':# , 'NUMPAD_0'
|
||||
self.lat.points_u = 2
|
||||
self.lat.points_v = 1
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'RIGHT_ARROW'} and event.value == 'PRESS' and event.ctrl:
|
||||
if self.lat.points_u < 20:
|
||||
self.lat.points_u += 1
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'LEFT_ARROW'} and event.value == 'PRESS' and event.ctrl:
|
||||
if self.lat.points_u > 1:
|
||||
self.lat.points_u -= 1
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'UP_ARROW'} and event.value == 'PRESS' and event.ctrl:
|
||||
if self.lat.points_v < 20:
|
||||
self.lat.points_v += 1
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'DOWN_ARROW'} and event.value == 'PRESS' and event.ctrl:
|
||||
if self.lat.points_v > 1:
|
||||
self.lat.points_v -= 1
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
# change modes
|
||||
if event.type in {'M'} and event.value == 'PRESS':
|
||||
self.auto_interp = False
|
||||
interp = 'KEY_BSPLINE' if self.lat.interpolation_type_u == 'KEY_LINEAR' else 'KEY_LINEAR'
|
||||
self.set_lattice_interp(interp)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
# Valid
|
||||
if event.type in {'RET', 'SPACE'}:
|
||||
if event.value == 'PRESS':
|
||||
#bpy.ops.ed.flush_edits()# TODO: find a way to get rid of undo-registered lattices tweaks
|
||||
self.restore_prefs(context)
|
||||
back_to_obj(self.gp_obj, self.gp_mode, self.org_lattice_toolset, context)
|
||||
apply_cage(self.gp_obj, self.cage)#must be in object mode
|
||||
|
||||
# back to original mode
|
||||
if self.gp_mode != 'OBJECT':
|
||||
bpy.ops.object.mode_set(mode=self.gp_mode)
|
||||
|
||||
context.area.header_text_set(None)#reset header
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# Abort ---
|
||||
# One Warning for Tab cancellation.
|
||||
if event.type == 'TAB' and event.value == 'PRESS':
|
||||
self.tab_press_ct += 1
|
||||
if self.tab_press_ct < 2:
|
||||
self.report({'WARNING'}, "Pressing TAB again will Cancel")
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if event.type in {'T'} and event.value == 'PRESS' and event.ctrl:# Retyped same shortcut
|
||||
self.cancel(context)
|
||||
return {'CANCELLED'}
|
||||
|
||||
if event.type in {'DEL', 'BACK_SPACE'} or self.tab_press_ct >= 2:#'ESC',
|
||||
self.cancel(context)
|
||||
return {'CANCELLED'}
|
||||
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
def set_lattice_interp(self, interp):
|
||||
self.lat.interpolation_type_u = self.lat.interpolation_type_v = self.lat.interpolation_type_w = interp
|
||||
|
||||
def cancel(self, context):
|
||||
self.restore_prefs(context)
|
||||
back_to_obj(self.gp_obj, self.gp_mode, self.org_lattice_toolset, context)
|
||||
cancel_cage(self.gp_obj, self.cage)
|
||||
context.area.header_text_set(None)
|
||||
if self.gp_mode != 'OBJECT':
|
||||
bpy.ops.object.mode_set(mode=self.gp_mode)
|
||||
|
||||
def store_prefs(self, context):
|
||||
# store_valierables <-< preferences
|
||||
self.use_drag_immediately = context.preferences.inputs.use_drag_immediately
|
||||
self.drag_threshold_mouse = context.preferences.inputs.drag_threshold_mouse
|
||||
self.drag_threshold_tablet = context.preferences.inputs.drag_threshold_tablet
|
||||
self.use_overlays = context.space_data.overlay.show_overlays
|
||||
|
||||
def restore_prefs(self, context):
|
||||
# preferences <-< store_valierables
|
||||
context.preferences.inputs.use_drag_immediately = self.use_drag_immediately
|
||||
context.preferences.inputs.drag_threshold_mouse = self.drag_threshold_mouse
|
||||
context.preferences.inputs.drag_threshold_tablet = self.drag_threshold_tablet
|
||||
context.space_data.overlay.show_overlays = self.use_overlays
|
||||
|
||||
def set_prefs(self, context):
|
||||
context.preferences.inputs.use_drag_immediately = True
|
||||
context.preferences.inputs.drag_threshold_mouse = 1
|
||||
context.preferences.inputs.drag_threshold_tablet = 3
|
||||
context.space_data.overlay.show_overlays = True
|
||||
|
||||
def invoke(self, context, event):
|
||||
## Restrict to 3D view
|
||||
if context.area.type != 'VIEW_3D':
|
||||
self.report({'WARNING'}, "View3D not found, cannot run operator")
|
||||
return {'CANCELLED'}
|
||||
|
||||
if not context.object:#do it in poll ?
|
||||
self.report({'ERROR'}, "No active objects found")
|
||||
return {'CANCELLED'}
|
||||
|
||||
# self.prefs = get_addon_prefs()#get_prefs
|
||||
self.org_lattice_toolset = None
|
||||
self.gp_mode = 'EDIT_GPENCIL'
|
||||
|
||||
# --- special Case of lattice revive modal, just after ctrl+Z back into lattice with modal stopped
|
||||
if context.mode == 'EDIT_LATTICE' and context.object.name == 'lattice_cage_deform' and len(context.object.vertex_groups):
|
||||
self.gp_obj = context.scene.objects.get(context.object.vertex_groups[0].name)
|
||||
if not self.gp_obj:
|
||||
self.report({'ERROR'}, "/!\\ Box Deform : Cannot find object to target")
|
||||
return {'CANCELLED'}
|
||||
if not self.gp_obj.grease_pencil_modifiers.get('tmp_lattice'):
|
||||
self.report({'ERROR'}, "/!\\ No 'tmp_lattice' modifiers on GP object")
|
||||
return {'CANCELLED'}
|
||||
self.cage = context.object
|
||||
self.lat = self.cage.data
|
||||
self.set_prefs(context)
|
||||
|
||||
context.window_manager.modal_handler_add(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
if context.object.type != 'GPENCIL':
|
||||
# self.report({'ERROR'}, "Works only on gpencil objects")
|
||||
## silent return
|
||||
return {'CANCELLED'}
|
||||
|
||||
#paint need VG workaround. object need good shortcut
|
||||
if context.mode not in ('EDIT_GPENCIL', 'OBJECT', 'PAINT_GPENCIL'):
|
||||
# self.report({'WARNING'}, "Works only in following GPencil modes: edit")# ERROR
|
||||
## silent return
|
||||
return {'CANCELLED'}
|
||||
|
||||
# bpy.ops.ed.undo_push(message="Box deform step")#don't work as expected (+ might be obsolete)
|
||||
# https://developer.blender.org/D6147 <- undo forget
|
||||
|
||||
self.gp_obj = context.object
|
||||
# Clean potential failed previous job (delete tmp lattice)
|
||||
mod = self.gp_obj.grease_pencil_modifiers.get('tmp_lattice')
|
||||
if mod:
|
||||
print('Deleted remaining lattice modifiers')
|
||||
self.gp_obj.grease_pencil_modifiers.remove(mod)
|
||||
|
||||
phantom_obj = context.scene.objects.get('lattice_cage_deform')
|
||||
if phantom_obj:
|
||||
print('Deleted remaining lattice object')
|
||||
delete_cage(phantom_obj)
|
||||
|
||||
if [m for m in self.gp_obj.grease_pencil_modifiers if m.type == 'GP_LATTICE']:
|
||||
self.report({'ERROR'}, "Grease pencil object already has a lattice modifier (can only have one)")
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
self.gp_mode = context.mode#store mode for restore
|
||||
|
||||
# All good, create lattice and start modal
|
||||
|
||||
# Create lattice (and switch to lattice edit) ----
|
||||
self.cage = view_cage(self.gp_obj)
|
||||
if isinstance(self.cage, str):#error, cage not created, display error
|
||||
self.report({'ERROR'}, self.cage)
|
||||
return {'CANCELLED'}
|
||||
|
||||
self.lat = self.cage.data
|
||||
|
||||
## usability toggles
|
||||
|
||||
## pref for clic drag -> if self.prefs.use_clic_drag:#Store the active tool since we will change it
|
||||
self.org_lattice_toolset = bpy.context.workspace.tools.from_space_view3d_mode(bpy.context.mode, create=False).idname# Tweaktoolcode
|
||||
|
||||
self.auto_interp = True#self.prefs.auto_swap_deform_type
|
||||
#store (scene properties needed in case of ctrlZ revival)
|
||||
self.store_prefs(context)
|
||||
self.set_prefs(context)
|
||||
context.window_manager.modal_handler_add(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
## --- KEYMAP
|
||||
|
||||
addon_keymaps = []
|
||||
def register_keymaps():
|
||||
addon = bpy.context.window_manager.keyconfigs.addon
|
||||
|
||||
km = addon.keymaps.new(name = "Grease Pencil", space_type = "EMPTY", region_type='WINDOW')
|
||||
kmi = km.keymap_items.new("gp.latticedeform", type ='T', value = "PRESS", ctrl = True)
|
||||
kmi.repeat = False
|
||||
addon_keymaps.append((km, kmi))
|
||||
|
||||
def unregister_keymaps():
|
||||
for km, kmi in addon_keymaps:
|
||||
km.keymap_items.remove(kmi)
|
||||
addon_keymaps.clear()
|
||||
|
||||
### --- REGISTER ---
|
||||
|
||||
def register():
|
||||
if bpy.app.background:
|
||||
return
|
||||
bpy.utils.register_class(GP_OT_latticeGpDeform)
|
||||
register_keymaps()
|
||||
|
||||
def unregister():
|
||||
if bpy.app.background:
|
||||
return
|
||||
unregister_keymaps()
|
||||
bpy.utils.unregister_class(GP_OT_latticeGpDeform)
|
|
@ -1,284 +0,0 @@
|
|||
from .utils import get_addon_prefs
|
||||
|
||||
## known issue: auto-perspective mess up when triggered out after rotation
|
||||
|
||||
import bpy
|
||||
import math
|
||||
import mathutils
|
||||
from bpy_extras.view3d_utils import location_3d_to_region_2d
|
||||
|
||||
## draw utils
|
||||
import gpu
|
||||
import bgl
|
||||
import blf
|
||||
from gpu_extras.batch import batch_for_shader
|
||||
from gpu_extras.presets import draw_circle_2d
|
||||
|
||||
"""
|
||||
Notes:
|
||||
Samuel.B:
|
||||
OpenGL drawing can be disabled by passing self.hud to False in invoke (mainly used for debugging)
|
||||
|
||||
Base script by Jum, simplified and modified to work in both view and camera with rotate axis method suggested by Christophe Seux
|
||||
|
||||
Jum:
|
||||
Script base. Thanks to bigLarry and Jum
|
||||
https://blender.stackexchange.com/questions/136183/rotating-camera-view-in-grease-pencil-draw-mode-in-blender-2-8
|
||||
"""
|
||||
|
||||
|
||||
def draw_callback_px(self, context):
|
||||
# 50% alpha, 2 pixel width line
|
||||
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
|
||||
bgl.glEnable(bgl.GL_BLEND)
|
||||
bgl.glLineWidth(2)
|
||||
|
||||
# init
|
||||
batch = batch_for_shader(shader, 'LINE_STRIP', {"pos": [self.center, self.initial_pos]})#self.vector_initial
|
||||
shader.bind()
|
||||
shader.uniform_float("color", (0.5, 0.5, 0.8, 0.6))
|
||||
batch.draw(shader)
|
||||
|
||||
batch = batch_for_shader(shader, 'LINE_STRIP', {"pos": [self.center, self.pos_current]})
|
||||
shader.bind()
|
||||
shader.uniform_float("color", (0.3, 0.7, 0.2, 0.5))
|
||||
batch.draw(shader)
|
||||
|
||||
## vector init vector current (substracted by center)
|
||||
# batch = batch_for_shader(shader, 'LINE_STRIP', {"pos": [self.vector_initial, self.vector_current]})
|
||||
# shader.bind()
|
||||
# shader.uniform_float("color", (0.5, 0.5, 0.5, 0.5))
|
||||
# batch.draw(shader)
|
||||
|
||||
# restore opengl defaults
|
||||
bgl.glLineWidth(1)
|
||||
bgl.glDisable(bgl.GL_BLEND)
|
||||
|
||||
## text
|
||||
|
||||
font_id = 0
|
||||
## draw text debug infos
|
||||
blf.position(font_id, 15, 30, 0)
|
||||
blf.size(font_id, 20, 72)
|
||||
blf.draw(font_id, f'angle: {math.degrees(self.angle):.1f}')
|
||||
|
||||
|
||||
class RC_OT_RotateCanvas(bpy.types.Operator):
|
||||
bl_idname = 'view3d.rotate_canvas'
|
||||
bl_label = 'Rotate Canvas'
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
# @classmethod
|
||||
# def poll(cls, context):
|
||||
# return context.region_data.view_perspective == 'CAMERA'
|
||||
"""
|
||||
def get_center_view(self, area, cam):
|
||||
'''
|
||||
https://blender.stackexchange.com/questions/6377/coordinates-of-corners-of-camera-view-border
|
||||
Thanks to ideasman42
|
||||
'''
|
||||
region_3d = area.spaces[0].region_3d
|
||||
for region in area.regions:
|
||||
if region.type == 'WINDOW':
|
||||
frame = cam.data.view_frame()
|
||||
# if cam.parent:
|
||||
# mat = cam.matrix_parent_inverse @ cam.matrix_world
|
||||
# # mat = cam.parent.matrix_world @ cam.matrix_world# not inverse from parent
|
||||
# else:
|
||||
# mat = cam.matrix_world
|
||||
|
||||
mat = cam.matrix_world
|
||||
frame = [mat @ v for v in frame]
|
||||
## bpy.context.scene.cursor.location = frame[1]#DEBUG
|
||||
frame_px = [location_3d_to_region_2d(region, region_3d, v) for v in frame]
|
||||
|
||||
center_x = frame_px[2].x + (frame_px[0].x - frame_px[2].x)/2
|
||||
center_y = frame_px[1].y + (frame_px[0].y - frame_px[1].y)/2
|
||||
return mathutils.Vector((center_x, center_y))
|
||||
return None """
|
||||
|
||||
def get_center_view(self, context, cam):
|
||||
'''
|
||||
https://blender.stackexchange.com/questions/6377/coordinates-of-corners-of-camera-view-border
|
||||
Thanks to ideasman42
|
||||
'''
|
||||
|
||||
frame = cam.data.view_frame()
|
||||
mat = cam.matrix_world
|
||||
frame = [mat @ v for v in frame]
|
||||
frame_px = [location_3d_to_region_2d(context.region, context.space_data.region_3d, v) for v in frame]
|
||||
center_x = frame_px[2].x + (frame_px[0].x - frame_px[2].x)/2
|
||||
center_y = frame_px[1].y + (frame_px[0].y - frame_px[1].y)/2
|
||||
|
||||
return mathutils.Vector((center_x, center_y))
|
||||
|
||||
def execute(self, context):
|
||||
if self.hud:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
|
||||
context.area.tag_redraw()
|
||||
if self.in_cam:
|
||||
self.cam.rotation_mode = self.org_rotation_mode
|
||||
return {'FINISHED'}
|
||||
|
||||
def modal(self, context, event):
|
||||
if event.type in {'MOUSEMOVE','INBETWEEN_MOUSEMOVE'}:
|
||||
# Get current mouse coordination (region)
|
||||
self.pos_current = mathutils.Vector((event.mouse_region_x, event.mouse_region_y))
|
||||
# Get current vector
|
||||
self.vector_current = (self.pos_current - self.center).normalized()
|
||||
# Calculates the angle between initial and current vectors
|
||||
self.angle = self.vector_initial.angle_signed(self.vector_current)#radian
|
||||
# print (math.degrees(self.angle), self.vector_initial, self.vector_current)
|
||||
|
||||
if self.in_cam:
|
||||
self.cam.matrix_world = self.cam_matrix
|
||||
# self.cam.rotation_euler = self.cam_init_euler
|
||||
self.cam.rotation_euler.rotate_axis("Z", self.angle)
|
||||
|
||||
else:#free view
|
||||
context.space_data.region_3d.view_matrix = self.view_matrix
|
||||
rot = context.space_data.region_3d.view_rotation
|
||||
rot = rot.to_euler()
|
||||
rot.rotate_axis("Z", self.angle)
|
||||
context.space_data.region_3d.view_rotation = rot.to_quaternion()
|
||||
|
||||
if event.type in {'RIGHTMOUSE', 'LEFTMOUSE', 'MIDDLEMOUSE'} and event.value == 'RELEASE':
|
||||
self.execute(context)
|
||||
return {'FINISHED'}
|
||||
|
||||
if event.type == 'ESC':#Cancel
|
||||
self.execute(context)
|
||||
if self.in_cam:
|
||||
self.cam.matrix_world = self.cam_matrix
|
||||
else:
|
||||
context.space_data.region_3d.view_matrix = self.view_matrix
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.hud = False
|
||||
self.angle = 0.0# for draw degub, else not needed
|
||||
self.in_cam = context.region_data.view_perspective == 'CAMERA'
|
||||
|
||||
if self.in_cam:
|
||||
# Get camera from scene
|
||||
self.cam = bpy.context.scene.camera
|
||||
|
||||
## avoid manipulating real cam or locked cams
|
||||
if not 'manip_cams' in [c.name for c in self.cam.users_collection]:
|
||||
self.report({'WARNING'}, 'Not in manipulation cam (draw/obj cam)')
|
||||
return {'CANCELLED'}
|
||||
|
||||
if self.cam.lock_rotation[:] != (False, False, False):
|
||||
self.report({'WARNING'}, 'Camera rotation is locked')
|
||||
return {'CANCELLED'}
|
||||
|
||||
self.center = self.get_center_view(context, self.cam)
|
||||
# store original rotation mode
|
||||
self.org_rotation_mode = self.cam.rotation_mode
|
||||
# set to euler to works with quaternions, restored at finish
|
||||
self.cam.rotation_mode = 'XYZ'
|
||||
# store camera matrix world
|
||||
self.cam_matrix = self.cam.matrix_world.copy()
|
||||
# self.cam_init_euler = self.cam.rotation_euler.copy()
|
||||
|
||||
else:
|
||||
self.center = mathutils.Vector((context.area.width/2, context.area.height/2))
|
||||
# store current view matrix
|
||||
self.view_matrix = context.space_data.region_3d.view_matrix.copy()
|
||||
|
||||
# Get current mouse coordination
|
||||
self.pos_current = mathutils.Vector((event.mouse_region_x, event.mouse_region_y))
|
||||
|
||||
self.initial_pos = self.pos_current# for draw debug, else no need
|
||||
# Calculate inital vector
|
||||
self.vector_initial = self.pos_current - self.center
|
||||
self.vector_initial.normalize()
|
||||
|
||||
# Initializes the current vector with the same initial vector.
|
||||
self.vector_current = self.vector_initial.copy()
|
||||
|
||||
args = (self, context)
|
||||
if self.hud:
|
||||
self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
|
||||
context.window_manager.modal_handler_add(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
class PREFS_OT_rebind(bpy.types.Operator):
|
||||
"""Rebind shortcuts canvas rotate shortcuts"""
|
||||
bl_idname = "prefs.rebind_shortcut"
|
||||
bl_label = "Rebind canvas rotate shortcut"
|
||||
bl_options = {'REGISTER', 'INTERNAL'}
|
||||
|
||||
def execute(self, context):
|
||||
unregister_keymaps()
|
||||
register_keymaps()
|
||||
return{'FINISHED'}
|
||||
|
||||
addon_keymaps = []
|
||||
def register_keymaps():
|
||||
pref = get_addon_prefs()
|
||||
if not pref.canvas_use_shortcut:
|
||||
return
|
||||
addon = bpy.context.window_manager.keyconfigs.addon
|
||||
|
||||
|
||||
""" ## NATIVE FREENAV BIND (left to right)
|
||||
km = bpy.context.window_manager.keyconfigs.addon.keymaps.get("3D View")
|
||||
if not km:
|
||||
km = addon.keymaps.new(name = "3D View", space_type = "VIEW_3D")
|
||||
# print('BINDING CANVAS ROTATE KEYMAPS')#Dbg
|
||||
if 'view3d.view_roll' not in km.keymap_items:
|
||||
# print('creating view3d.view_roll')#Dbg
|
||||
# kmi = km.keymap_items.new("view3d.view_roll", type = 'MIDDLEMOUSE', value = "PRESS", ctrl=True, shift=False, alt=True)#PRESS#CLICK_DRAG
|
||||
kmi = km.keymap_items.new("view3d.view_roll", type=pref.mouse_click, value = "PRESS", alt=pref.use_alt, ctrl=pref.use_ctrl, shift=pref.use_shift, any=False)#PRESS#CLICK_DRAG
|
||||
kmi.properties.type = 'ANGLE'
|
||||
addon_keymaps.append(km)
|
||||
"""
|
||||
km = bpy.context.window_manager.keyconfigs.addon.keymaps.get("3D View")
|
||||
if not km:
|
||||
km = addon.keymaps.new(name = "3D View", space_type = "VIEW_3D")
|
||||
|
||||
if 'view3d.rotate_canvas' not in km.keymap_items:
|
||||
# print('creating view3d.rotate_canvas')#Dbg
|
||||
## keymap to operator cam space (in grease pencil mode only ?)
|
||||
km = addon.keymaps.new(name='3D View', space_type='VIEW_3D')#EMPTY #Grease Pencil
|
||||
# kmi = km.keymap_items.new('view3d.rotate_canvas', 'MIDDLEMOUSE', 'PRESS', ctrl=True, shift=False, alt=True)
|
||||
kmi = km.keymap_items.new('view3d.rotate_canvas', type=pref.mouse_click, value="PRESS", alt=pref.use_alt, ctrl=pref.use_ctrl, shift=pref.use_shift, any=False)
|
||||
addon_keymaps.append((km, kmi))
|
||||
# print(addon_keymaps)
|
||||
|
||||
def unregister_keymaps():
|
||||
# print('UNBIND CANVAS ROTATE KEYMAPS')#Dbg
|
||||
for km, kmi in addon_keymaps:
|
||||
km.keymap_items.remove(kmi)
|
||||
addon_keymaps.clear()
|
||||
# del addon_keymaps[:]
|
||||
|
||||
canvas_classes = (
|
||||
PREFS_OT_rebind,
|
||||
RC_OT_RotateCanvas,
|
||||
# RC_OT_RotateCanvasFreeNav
|
||||
)
|
||||
|
||||
def register():
|
||||
if not bpy.app.background:
|
||||
for cls in canvas_classes:
|
||||
bpy.utils.register_class(cls)
|
||||
register_keymaps()
|
||||
# wm = bpy.context.window_manager
|
||||
# km = wm.keyconfigs.addon.keymaps.new(name='Grease Pencil', space_type='EMPTY')
|
||||
# kmi = km.keymap_items.new('view3d.rotate_canvas', 'MIDDLEMOUSE', 'PRESS', ctrl=True, shift=False, alt=True)
|
||||
# addon_keymaps.append(km)
|
||||
|
||||
def unregister():
|
||||
if not bpy.app.background:
|
||||
unregister_keymaps()
|
||||
for cls in reversed(canvas_classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# register()
|
|
@ -54,8 +54,6 @@ Add an "on save" Handler that trigger relative remap of all path.
|
|||
- Choose key to Auto bind in addon prefs (since 0.9.3).
|
||||
> Manual setup: Add two keymap shortcut in _windows_ or _screen(global)_ with indentifier `screen.gp_keyframe_jump`, one should have `next` toggled off to jump back
|
||||
|
||||
- Rotate canvas with a clic + modifier combo (default is `ctrl + alt + MID-mouse`), can be change in addon preferences.
|
||||
|
||||
- GP paint cutter tool temporary switch shortcut
|
||||
- Map manually to a key with `wm.temp_cutter` (This one needs "Any" as press mode) or `wm.sticky_cutter` (Modal sticky-key version)
|
||||
|
||||
|
@ -103,6 +101,11 @@ Panel in sidebar : 3D view > sidebar 'N' > Gpencil
|
|||
|
||||
## Changelog:
|
||||
|
||||
1.0.0:
|
||||
|
||||
- Compatible with official grease pencil tools
|
||||
- removed box deform and rotate canvas that existed in other
|
||||
|
||||
0.9.3:
|
||||
|
||||
- feat: keyframe jump keys are now auto-binded
|
||||
|
|
|
@ -37,10 +37,6 @@ Expose les options suivantes:
|
|||
|
||||
L'action cam (peut-être renommé en follow_cam ?) fonctionne sur le même principe que la draw sauf qu'elle se parente à l'objet selectionné. Le but est de pouvoir suivre un objet en mouvement pour le dessiner en continu sans nécessairement désactiver les anims. Concrètement, désactiver les animation d'objets est sans doute plus clean et sans doute moins galère donc option a potentiellement retirer dans le futur.
|
||||
|
||||
**Rotate canvas** (`ctrl + alt + clic-droit`) - Différence avec celui intégré a grease pencil tools : la rotation en vue cam n'est possible que si on est dans une caméra de manipulation (`manip_cam`) pour éviter de casser l'anim le roll de la cam principale.
|
||||
|
||||
**Box deform** (`Ctrl+T`) - Déformation 4 coins (Déjà dans _Grease pencil tools_ donc a potentiellement retirer pour éviter de possible confits/redondances, mais d'un autre côté la version intégrée peut être customisée et corriger d'éventuel souci sans attendre les updates de la version native...)
|
||||
|
||||
**GP keyframe jump** (auto bind et personnalisable dans les addon prefs depuis 0.9.3) - Essentiel ! Permet d'ajouter une ou plusieurs paire de raccourcis pour aller de keyframe en keyframe (filtrage du saut personnalisable). Lance l'operateur `screen.gp_keyframe_jump`, (si ajout manuel, rajouter une seconde keymap avec la propriété `next` décoché pour faire un saut arrière)
|
||||
|
||||
**Breakdown en mode objet** (`Shift+E`) - Breakdown en pourcentage entre les deux keyframes (pose une clé si l’auto-key est actif et utilise le keying set si actif). Même comportement et raccourci que le breakdown de bones en pose mode (juste qu'il n'existait bizzarement pas en objet)
|
||||
|
@ -68,6 +64,10 @@ Permet également de copier l'intégralité des layers selectionnés avec le bou
|
|||
- Warn if there are some disabled animation (and list datapath)
|
||||
- Set onion skin filter to 'All type' (this became default in blender 2.91, guess who asked ;) )
|
||||
|
||||
EDIT: _rotate canvas_ et _box deform_ ont été retiré dans la version 1.0 car déja intégré à l'addon natif **grease pencil tools** depuis la 2.91 (activez simplement cet addon)
|
||||
> **Rotate canvas** (`ctrl + alt + clic-droit`) - Différence avec celui intégré a grease pencil tools : la rotation en vue cam n'est possible que si on est dans une caméra de manipulation (`manip_cam`) pour éviter de casser l'anim le roll de la cam principale.
|
||||
|
||||
> **Box deform** (`Ctrl+T`) - Déformation 4 coins (Déjà dans _Grease pencil tools_ donc a potentiellement retirer pour éviter de possible confits/redondances, mais d'un autre côté la version intégrée peut être customisée et corriger d'éventuel souci sans attendre les updates de la version native...)
|
||||
|
||||
### moins important
|
||||
|
||||
|
|
80
__init__.py
80
__init__.py
|
@ -12,10 +12,10 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
bl_info = {
|
||||
"name": "gp toolbox",
|
||||
"name": "GP toolbox",
|
||||
"description": "Set of tools for Grease Pencil in animation production",
|
||||
"author": "Samuel Bernou",
|
||||
"version": (0, 9, 3),
|
||||
"version": (1, 0, 0),
|
||||
"blender": (2, 91, 0),
|
||||
"location": "sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
|
||||
"warning": "",
|
||||
|
@ -35,12 +35,10 @@ from .GP_guided_colorize import GP_colorize
|
|||
## direct tools
|
||||
from . import OP_breakdowner
|
||||
from . import OP_temp_cutter
|
||||
from . import OP_canvas_rotate
|
||||
from . import OP_playblast_bg
|
||||
from . import OP_playblast
|
||||
from . import OP_helpers
|
||||
from . import OP_keyframe_jump
|
||||
from . import OP_box_deform
|
||||
from . import OP_cursor_snap_canvas
|
||||
from . import OP_palettes
|
||||
from . import OP_file_checker
|
||||
|
@ -82,7 +80,6 @@ class GPTB_prefs(bpy.types.AddonPreferences):
|
|||
items=(('PREF', "Preferences", "Change some preferences of the modal"),
|
||||
('MAN_OPS', "Operator", "Operator to add Manually"),
|
||||
# ('TUTO', "Tutorial", "How to use the tool"),
|
||||
# ('GMIC', "Gmic color", "Options to use gmic to colorize"),
|
||||
('UPDATE', "Update", "Check and apply updates"),
|
||||
# ('KEYMAP', "Keymap", "customise the default keymap"),
|
||||
),
|
||||
|
@ -176,36 +173,6 @@ class GPTB_prefs(bpy.types.AddonPreferences):
|
|||
default=False,
|
||||
)
|
||||
|
||||
## Canvas rotate
|
||||
canvas_use_shortcut: BoolProperty(
|
||||
name = "Use Default Shortcut",
|
||||
description = "Use default shortcut: mouse double-click + modifier",
|
||||
default = True)
|
||||
|
||||
mouse_click : EnumProperty(
|
||||
name="Mouse button", description="click on right/left/middle mouse button in combination with a modifier to trigger alignement",
|
||||
default='RIGHTMOUSE',
|
||||
items=(
|
||||
('RIGHTMOUSE', 'Right click', 'Use click on Right mouse button', 'MOUSE_RMB', 0),
|
||||
('LEFTMOUSE', 'Left click', 'Use click on Left mouse button', 'MOUSE_LMB', 1),
|
||||
('MIDDLEMOUSE', 'Mid click', 'Use click on Mid mouse button', 'MOUSE_MMB', 2),
|
||||
))
|
||||
|
||||
use_shift: BoolProperty(
|
||||
name = "combine with shift",
|
||||
description = "add shift combined with double click to trigger alignement",
|
||||
default = False)
|
||||
|
||||
use_alt: BoolProperty(
|
||||
name = "combine with alt",
|
||||
description = "add alt combined with double click to trigger alignement (default)",
|
||||
default = True)
|
||||
|
||||
use_ctrl: BoolProperty(
|
||||
name = "combine with ctrl",
|
||||
description = "add ctrl combined with double click to trigger alignement",
|
||||
default = True)
|
||||
|
||||
## default active tool to use
|
||||
select_active_tool : EnumProperty(
|
||||
name="Default selection tool", description="Active tool to set when launching check fix scene",
|
||||
|
@ -301,10 +268,6 @@ class GPTB_prefs(bpy.types.AddonPreferences):
|
|||
|
||||
|
||||
if self.pref_tabs == 'PREF':
|
||||
box = layout.box()
|
||||
box.label(text='Random color options:')
|
||||
box.prop(self, 'separator')
|
||||
|
||||
box = layout.box()
|
||||
box.label(text='Project settings')
|
||||
|
||||
|
@ -367,34 +330,6 @@ class GPTB_prefs(bpy.types.AddonPreferences):
|
|||
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")
|
||||
|
||||
# box.separator()## Canvas
|
||||
box = layout.box()
|
||||
box.label(text='Canvas rotate options:')
|
||||
box.prop(self, "canvas_use_shortcut", text='Bind shortcuts')
|
||||
|
||||
if self.canvas_use_shortcut:
|
||||
row = box.row()
|
||||
row.label(text="After changes, use the Bind/Rebind button")#icon=""
|
||||
row.operator("prefs.rebind_shortcut", text='Bind/Rebind shortcuts', icon='FILE_REFRESH')#EVENT_SPACEKEY
|
||||
row = box.row(align = True)
|
||||
row.prop(self, "use_ctrl", text='Ctrl')#, expand=True
|
||||
row.prop(self, "use_alt", text='Alt')#, expand=True
|
||||
row.prop(self, "use_shift", text='Shift')#, expand=True
|
||||
row.prop(self, "mouse_click",text='')#expand=True
|
||||
|
||||
if not self.use_ctrl and not self.use_alt and not self.use_shift:
|
||||
box.label(text="Choose at least one modifier to combine with click (default: Ctrl+Alt)", icon="ERROR")# INFO
|
||||
|
||||
else:
|
||||
box.label(text="No hotkey has been set automatically. Following operators needs to be set manually:", icon="ERROR")
|
||||
box.label(text="view3d.rotate_canvas")
|
||||
|
||||
# TODO get that off once proper register update from properties
|
||||
if self.canvas_use_shortcut:
|
||||
OP_canvas_rotate.register_keymaps()
|
||||
else:
|
||||
OP_canvas_rotate.unregister_keymaps()
|
||||
|
||||
## Active tool
|
||||
box = layout.box()
|
||||
box.label(text='Autofix check button options:')
|
||||
|
@ -402,7 +337,12 @@ class GPTB_prefs(bpy.types.AddonPreferences):
|
|||
|
||||
|
||||
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
|
||||
|
@ -466,7 +406,6 @@ def register():
|
|||
addon_updater_ops.register(bl_info)
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
OP_box_deform.register()
|
||||
OP_helpers.register()
|
||||
OP_keyframe_jump.register()
|
||||
OP_file_checker.register()
|
||||
|
@ -476,7 +415,6 @@ def register():
|
|||
OP_playblast_bg.register()
|
||||
OP_playblast.register()
|
||||
OP_palettes.register()
|
||||
OP_canvas_rotate.register()
|
||||
OP_cursor_snap_canvas.register()
|
||||
OP_render.register()
|
||||
OP_copy_paste.register()
|
||||
|
@ -497,7 +435,6 @@ def unregister():
|
|||
OP_copy_paste.unregister()
|
||||
OP_render.unregister()
|
||||
OP_cursor_snap_canvas.unregister()
|
||||
OP_canvas_rotate.unregister()
|
||||
OP_palettes.unregister()
|
||||
OP_file_checker.unregister()
|
||||
OP_helpers.unregister()
|
||||
|
@ -507,7 +444,6 @@ def unregister():
|
|||
GP_colorize.unregister()## GP_guided_colorize.
|
||||
OP_playblast_bg.unregister()
|
||||
OP_playblast.unregister()
|
||||
OP_box_deform.unregister()
|
||||
del bpy.types.Scene.gptoolprops
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ def register_keymaps():
|
|||
# km = addon.keymaps.new(name = "3D View", space_type = "VIEW_3D")# in 3D context
|
||||
# km = addon.keymaps.new(name = "Window", space_type = "EMPTY")# from everywhere
|
||||
|
||||
## try initiate
|
||||
km = addon.keymaps.new(name = "Grease Pencil Stroke Sculpt Mode", space_type = "EMPTY", region_type='WINDOW')
|
||||
|
||||
kmi = km.keymap_items.new('wm.context_toggle', type='ONE', value='PRESS')
|
||||
|
@ -24,11 +23,9 @@ def register_keymaps():
|
|||
addon_keymaps.append((km, kmi))
|
||||
|
||||
def unregister_keymaps():
|
||||
# wm = bpy.context.window_manager
|
||||
for km, kmi in addon_keymaps:
|
||||
km.keymap_items.remove(kmi)
|
||||
|
||||
# wm.keyconfigs.addon.keymaps.remove(km)
|
||||
addon_keymaps.clear()
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue