Layer actions and navigations features

1.9.0

- feat: New shortcuts:
  - `F2` in Paint and Edit to rename active layer
  - `Insert` add a new layer (same as Krita)
  - `Shift + Insert` add a new layer and immediately pop-up a rename box
  - `page up / page down` change active layer up/down with a temporary fade (settings in addon prefs)
- fix: error when tweaking `gp.duplicate_send_to_layer` shortcut
gpv2
Pullusb 2021-12-22 14:11:31 +01:00
parent 3c7477c442
commit 97b09444ab
8 changed files with 379 additions and 32 deletions

View File

@ -1,5 +1,15 @@
# Changelog # Changelog
1.9.0
- feat: New shortcuts:
- `F2` in Paint and Edit to rename active layer
- `Insert` add a new layer (same as Krita)
- `Shift + Insert` add a new layer and immediately pop-up a rename box
- `page up / page down` change active layer up/down with a temporary fade (settings in addon prefs)
- fix: error when tweaking `gp.duplicate_send_to_layer` shortcut
1.8.1 1.8.1
- fix: Gp clipboard paste `Paste layers` don't skip empty frames anymore - fix: Gp clipboard paste `Paste layers` don't skip empty frames anymore
@ -13,7 +23,6 @@
1.7.8 1.7.8
- fix: reset rotation in draw cam mode keep view in the same place (counter camera rotation) - fix: reset rotation in draw cam mode keep view in the same place (counter camera rotation)
- code: initial enhancement for palette linking
1.7.7 1.7.7

View File

@ -302,7 +302,7 @@ class OBJ_OT_breakdown_obj_anim(bpy.types.Operator):
### --- KEYMAP --- ### --- KEYMAP ---
breakdowner_addon_keymaps = [] addon_keymaps = []
def register_keymaps(): def register_keymaps():
if bpy.app.background: if bpy.app.background:
return return
@ -322,16 +322,15 @@ def register_keymaps():
if ops_id not in km.keymap_items: if ops_id not in km.keymap_items:
km = addon.keymaps.new(name='3D View', space_type='VIEW_3D')#EMPTY km = addon.keymaps.new(name='3D View', space_type='VIEW_3D')#EMPTY
kmi = km.keymap_items.new(ops_id, type="E", value="PRESS", shift=True) kmi = km.keymap_items.new(ops_id, type="E", value="PRESS", shift=True)
breakdowner_addon_keymaps.append((km, kmi)) addon_keymaps.append((km, kmi))
def unregister_keymaps(): def unregister_keymaps():
if bpy.app.background: if bpy.app.background:
return return
for km, kmi in breakdowner_addon_keymaps: for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi) km.keymap_items.remove(kmi)
breakdowner_addon_keymaps.clear() addon_keymaps.clear()
# del breakdowner_addon_keymaps[:]
### --- REGISTER --- ### --- REGISTER ---

View File

@ -4,8 +4,10 @@ from bpy.types import Operator
def get_layer_list(self, context): def get_layer_list(self, context):
'''return (identifier, name, description) of enum content''' '''return (identifier, name, description) of enum content'''
if not context:
return [('None', 'None','None')]
if not context.object: if not context.object:
return return [('None', 'None','None')]
return [(l.info, l.info, '') for l in context.object.data.layers if l != context.object.data.layers.active] return [(l.info, l.info, '') for l in context.object.data.layers if l != context.object.data.layers.active]
# try: # try:
# except: # except:
@ -23,7 +25,8 @@ class GPTB_OT_duplicate_send_to_layer(Operator) :
layers_enum : bpy.props.EnumProperty( layers_enum : bpy.props.EnumProperty(
name="Duplicate to layers", name="Duplicate to layers",
description="Duplicate selected keys in active layer and send them to choosen layer", description="Duplicate selected keys in active layer and send them to choosen layer",
items=get_layer_list items=get_layer_list,
options={'HIDDEN'},
) )
delete_source : bpy.props.BoolProperty(default=False, options={'SKIP_SAVE'}) delete_source : bpy.props.BoolProperty(default=False, options={'SKIP_SAVE'})
@ -110,12 +113,10 @@ def register_keymaps():
# if not pref.kfj_use_shortcut: # if not pref.kfj_use_shortcut:
# return # return
addon = bpy.context.window_manager.keyconfigs.addon addon = bpy.context.window_manager.keyconfigs.addon
# km = addon.keymaps.new(name = "Screen", space_type = "EMPTY")
km = addon.keymaps.new(name = "Dopesheet", space_type = "DOPESHEET_EDITOR") km = addon.keymaps.new(name = "Dopesheet", space_type = "DOPESHEET_EDITOR")
kmi = km.keymap_items.new('gp.duplicate_send_to_layer', type='D', value="PRESS", ctrl=True, shift=True) kmi = km.keymap_items.new('gp.duplicate_send_to_layer', type='D', value="PRESS", ctrl=True, shift=True)
addon_keymaps.append((km,kmi)) addon_keymaps.append((km,kmi))
# km = addon.keymaps.new(name = "Dopesheet", space_type = "DOPESHEET_EDITOR") # try duplicating km (seem to be error at unregsiter) # km = addon.keymaps.new(name = "Dopesheet", space_type = "DOPESHEET_EDITOR") # try duplicating km (seem to be error at unregsiter)
kmi = km.keymap_items.new('gp.duplicate_send_to_layer', type='X', value="PRESS", ctrl=True, shift=True) kmi = km.keymap_items.new('gp.duplicate_send_to_layer', type='X', value="PRESS", ctrl=True, shift=True)
kmi.properties.delete_source = True kmi.properties.delete_source = True

View File

@ -633,6 +633,107 @@ def subscribe_handler(dummy):
) )
##--- Add layers
class GPTB_PT_layer_name_ui(bpy.types.Panel):
bl_space_type = 'TOPBAR' # dummy
bl_region_type = 'HEADER'
bl_options = {'INSTANCED'}
bl_label = 'Layer Rename'
bl_ui_units_x = 14
def invoke(self, context, event):
# all_addons_l = get_modifier_list()
wm = context.window_manager
wm.invoke_props_dialog(self) # , width=600
return {'FINISHED'}
def draw(self, context):
layout = self.layout
# def row_with_icon(layout, icon):
# # Edit first editable button in popup
# row = layout.row()
# row.activate_init = True
# row.label(icon=icon)
# return row
# row = row_with_icon(layout, 'OUTLINER_DATA_GP_LAYER')
row = layout.row()
row.activate_init = True
row.label(icon='OUTLINER_DATA_GP_LAYER')
row.prop(context.object.data.layers.active, 'info', text='')
def add_layer(context):
bpy.ops.gpencil.layer_add()
context.object.data.layers.active.use_lights = False
class GPTB_OT_add_gp_layer_with_rename(Operator):
bl_idname = "gp.add_layer_rename"
bl_label = "Add Rename GPencil Layer"
bl_description = "Create a new gp layer with use light toggled off and popup a rename box"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'GPENCIL'
def execute(self, context):
add_layer(context)
bpy.ops.wm.call_panel(name="GPTB_PT_layer_name_ui", keep_open = False)
return {"FINISHED"}
class GPTB_OT_add_gp_layer(Operator):
bl_idname = "gp.add_layer"
bl_label = "Add GPencil Layer"
bl_description = "Create a new gp layer with use light toggled off"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'GPENCIL'
def execute(self, context):
add_layer(context)
return {"FINISHED"}
addon_keymaps = []
def register_keymaps():
addon = bpy.context.window_manager.keyconfigs.addon
##---# Insert Layers
## Insert new gp layer (with no use_light)
km = addon.keymaps.new(name = "Grease Pencil", space_type = "EMPTY") # global (only paint ?)
kmi = km.keymap_items.new('gp.add_layer', type='INSERT', value='PRESS')
addon_keymaps.append((km, kmi))
## Insert new gp layer (with no use_light and immediately pop up a box to rename)
# km = addon.keymaps.new(name = "Grease Pencil", space_type = "EMPTY") # global (only paint ?)
kmi = km.keymap_items.new('gp.add_layer_rename', type='INSERT', value='PRESS', shift=True)
addon_keymaps.append((km, kmi))
##---# F2 rename calls
## Direct rename active layer in Paint mode
km = addon.keymaps.new(name = "Grease Pencil Stroke Paint Mode", space_type = "EMPTY")
kmi = km.keymap_items.new('wm.call_panel', type='F2', value='PRESS')
kmi.properties.name = 'GPTB_PT_layer_name_ui'
kmi.properties.keep_open = False
addon_keymaps.append((km, kmi))
## Same in edit mode
km = addon.keymaps.new(name = "Grease Pencil Stroke Edit Mode", space_type = "EMPTY")
kmi = km.keymap_items.new('wm.call_panel', type='F2', value='PRESS')
kmi.properties.name = 'GPTB_PT_layer_name_ui'
kmi.properties.keep_open = False
addon_keymaps.append((km, kmi))
def unregister_keymaps():
for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi)
addon_keymaps.clear()
classes=( classes=(
GPTB_OT_rename_gp_layer, GPTB_OT_rename_gp_layer,
GPTB_OT_layer_name_build, GPTB_OT_layer_name_build,
@ -640,9 +741,14 @@ classes=(
GPTB_OT_layer_new_group, GPTB_OT_layer_new_group,
GPTB_OT_select_set_same_prefix, GPTB_OT_select_set_same_prefix,
GPTB_OT_select_set_same_color, GPTB_OT_select_set_same_color,
## Layer add and pop-up rename
GPTB_PT_layer_name_ui, # pop-up
GPTB_OT_add_gp_layer_with_rename, # shift+Ins
GPTB_OT_add_gp_layer, # Ins
) )
def register(): def register():
for cls in classes: for cls in classes:
bpy.utils.register_class(cls) bpy.utils.register_class(cls)
@ -650,8 +756,10 @@ def register():
bpy.types.DOPESHEET_HT_header.append(gpencil_dopesheet_header) bpy.types.DOPESHEET_HT_header.append(gpencil_dopesheet_header)
bpy.types.GPENCIL_MT_layer_context_menu.append(gpencil_layer_dropdown_menu) bpy.types.GPENCIL_MT_layer_context_menu.append(gpencil_layer_dropdown_menu)
bpy.app.handlers.load_post.append(subscribe_handler) # need to restart after first activation bpy.app.handlers.load_post.append(subscribe_handler) # need to restart after first activation
register_keymaps()
def unregister(): def unregister():
unregister_keymaps()
bpy.app.handlers.load_post.remove(subscribe_handler) bpy.app.handlers.load_post.remove(subscribe_handler)
bpy.types.GPENCIL_MT_layer_context_menu.remove(gpencil_layer_dropdown_menu) bpy.types.GPENCIL_MT_layer_context_menu.remove(gpencil_layer_dropdown_menu)
bpy.types.DOPESHEET_HT_header.remove(gpencil_dopesheet_header) bpy.types.DOPESHEET_HT_header.remove(gpencil_dopesheet_header)

142
OP_layer_nav.py Normal file
View File

@ -0,0 +1,142 @@
import bpy
from . import utils
class GPT_OT_layer_nav(bpy.types.Operator):
bl_idname = "gp.layer_nav"
bl_label = "GP Layer Navigator"
bl_description = "Change active GP layer and highlight active for a moment"
bl_options = {'REGISTER', 'INTERNAL', 'UNDO'}
direction : bpy.props.EnumProperty(
name='direction',
items=(('NONE', 'None', ''),('UP', 'Up', ''),('DOWN', 'Down', '')),
default='NONE',
description='Direction to change layer in active GPencil stack',
options={'SKIP_SAVE'})
## hardcoded values
# interval = 0.04 # 0.1
# limit = 1.8
# fade_val = 0.35
# use_fade_in = True
# fade_in_time = 0.5
def invoke(self, context, event):
## initialise vvalue from prefs
prefs = utils.get_addon_prefs()
if not prefs.nav_use_fade:
if self.direction == 'DOWN' or (event.type == 'PAGE_DOWN' and event.value == 'PRESS'):
utils.iterate_selector(context.object.data.layers, 'active_index', -1, info_attr = 'info')
if self.direction == 'UP' or (event.type == 'PAGE_UP' and event.value == 'PRESS'):
utils.iterate_selector(context.object.data.layers, 'active_index', 1, info_attr = 'info')
return {'FINISHED'}
self.interval = prefs.nav_interval
self.limit = prefs.nav_limit
self.fade_val = prefs.nav_fade_val
self.use_fade_in = prefs.nav_use_fade_in
self.fade_in_time = prefs.nav_fade_in_time
self.lapse = 0
wm = context.window_manager
args = (self, context)
if context.space_data.overlay.use_gpencil_fade_layers:
self.fade_target = context.space_data.overlay.gpencil_fade_layer
else:
self.fade_target = 1.0
self.fade_start = self.limit - self.fade_in_time
self.first = True
self._timer = wm.event_timer_add(self.interval, window=context.window) # 0.1
wm.modal_handler_add(self)
return {'RUNNING_MODAL'}
def store_settings(self, context):
self.org_use_gpencil_fade_layers = context.space_data.overlay.use_gpencil_fade_layers
self.org_gpencil_fade_layer = context.space_data.overlay.gpencil_fade_layer
context.space_data.overlay.use_gpencil_fade_layers = True
context.space_data.overlay.gpencil_fade_layer = self.fade_val
def modal(self, context, event):
trigger = False
if event.type in {'RIGHTMOUSE', 'ESC', 'LEFTMOUSE'}:
self.stop_mod(context)
return {'CANCELLED'}
if event.type == 'TIMER':
self.lapse += self.interval
if self.lapse >= self.limit:
self.stop_mod(context)
return {'FINISHED'}
## Fade
if self.use_fade_in and (self.lapse > self.fade_start):
fade = utils.transfer_value(self.lapse, self.fade_start, self.limit, self.fade_val, self.fade_target)
# print(f'lapse {self.lapse} - fade {fade}')
context.space_data.overlay.gpencil_fade_layer = fade
if self.direction == 'DOWN' or (event.type == 'PAGE_DOWN' and event.value == 'PRESS'):
_val = utils.iterate_selector(context.object.data.layers, 'active_index', -1, info_attr = 'info')
trigger = True
if self.direction == 'UP' or (event.type == 'PAGE_UP' and event.value == 'PRESS'):
_val = utils.iterate_selector(context.object.data.layers, 'active_index', 1, info_attr = 'info')
# utils.iterate_selector(bpy.context.scene.grease_pencil.layers, 'active_index', 1, info_attr = 'info')#layers
trigger = True
if trigger:
self.direction = 'NONE'
if self.first:
self.store_settings(context)
self.first=False
if self.use_fade_in:
# reset fade to wanted value
context.space_data.overlay.gpencil_fade_layer = self.fade_val
self.lapse = 0 # reset counter
return {'RUNNING_MODAL'}#running modal prevent original usage to be triggered (capture keys)
return {'PASS_THROUGH'}
def stop_mod(self, context):
# restore fade
context.space_data.overlay.use_gpencil_fade_layers = self.org_use_gpencil_fade_layers
context.space_data.overlay.gpencil_fade_layer = self.org_gpencil_fade_layer
wm = context.window_manager
wm.event_timer_remove(self._timer)
addon_keymaps = []
def register_keymap():
addon = bpy.context.window_manager.keyconfigs.addon
km = addon.keymaps.new(name = "Grease Pencil Stroke Paint Mode", space_type = "EMPTY")
kmi = km.keymap_items.new('gp.layer_nav', type='PAGE_UP', value='PRESS')
kmi.properties.direction = 'UP'
addon_keymaps.append((km, kmi))
kmi = km.keymap_items.new('gp.layer_nav', type='PAGE_DOWN', value='PRESS')
kmi.properties.direction = 'DOWN'
addon_keymaps.append((km, kmi))
def unregister_keymap():
for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi)
addon_keymaps.clear()
def register():
bpy.utils.register_class(GPT_OT_layer_nav)
register_keymap()
def unregister():
unregister_keymap()
bpy.utils.unregister_class(GPT_OT_layer_nav)

View File

@ -15,7 +15,7 @@ bl_info = {
"name": "GP toolbox", "name": "GP toolbox",
"description": "Tool set for Grease Pencil in animation production", "description": "Tool set for Grease Pencil in animation production",
"author": "Samuel Bernou, Christophe Seux", "author": "Samuel Bernou, Christophe Seux",
"version": (1, 8, 1), "version": (1, 9, 0),
"blender": (2, 91, 0), "blender": (2, 91, 0),
"location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties", "location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
"warning": "", "warning": "",
@ -51,6 +51,7 @@ from . import OP_depth_move
from . import OP_key_duplicate_send from . import OP_key_duplicate_send
from . import OP_layer_manager from . import OP_layer_manager
from . import OP_layer_picker from . import OP_layer_picker
from . import OP_layer_nav
from . import OP_material_picker from . import OP_material_picker
from . import OP_eraser_brush from . import OP_eraser_brush
from . import TOOL_eraser_brush from . import TOOL_eraser_brush
@ -310,6 +311,38 @@ class GPTB_prefs(bpy.types.AddonPreferences):
fixprops: bpy.props.PointerProperty(type = GP_PG_FixSettings) fixprops: bpy.props.PointerProperty(type = GP_PG_FixSettings)
## GP Layer navigator
nav_use_fade : BoolProperty(
name='Fade Inactive Layers',
description='Fade Inactive layers to determine active layer in a glimpse',
default=True)
nav_fade_val : FloatProperty(
name='Fade Value',
description='Fade value for other layers when navigating (0=invisible)',
default=0.35, min=0.0, max=0.95, step=1, precision=2)
nav_limit : FloatProperty(
name='Fade Duration',
description='Time of other layer faded when using layer navigation',
default=1.4, min=0.1, max=5, step=2, precision=1, subtype='TIME', unit='TIME')
nav_use_fade_in : BoolProperty(
name='Progressive Fade Back',
description='Use a fade on other layer when navigating',
default=True)
nav_fade_in_time : FloatProperty(
name='Fade-In Time',
description='Duration of the fade',
default=0.5, min=0.1, max=5, step=2, precision=2, subtype='TIME', unit='TIME')
nav_interval : FloatProperty(
name='Refresh Rate',
description='Refresh rate for fade updating (upper value means stepped fade)',
default=0.04, min=0.01, max=0.5, step=3, precision=2, subtype='TIME', unit='TIME')
## Temp cutter ## Temp cutter
# temp_cutter_use_shortcut: BoolProperty( # temp_cutter_use_shortcut: BoolProperty(
# name = "Use temp cutter Shortcut", # name = "Use temp cutter Shortcut",
@ -415,6 +448,21 @@ class GPTB_prefs(bpy.types.AddonPreferences):
box = layout.box() box = layout.box()
box.label(text='Tools options:') box.label(text='Tools options:')
subbox= box.box()
subbox.label(text='Layer Navigation')
col = subbox.column()
col.prop(self, 'nav_use_fade')
if self.nav_use_fade:
row = col.row()
row.prop(self, 'nav_fade_val')
row.prop(self, 'nav_limit')
row = subbox.row(align=False)
row.prop(self, 'nav_use_fade_in')
if self.nav_use_fade_in:
row.prop(self, 'nav_fade_in_time', text='Fade Back Time')
# row.prop(self, 'nav_interval') # Do not expose refresh rate for now, not usefull to user...
box.prop(self, 'use_precise_eraser') box.prop(self, 'use_precise_eraser')
if self.pref_tabs == 'KEYS': if self.pref_tabs == 'KEYS':
@ -427,14 +475,15 @@ class GPTB_prefs(bpy.types.AddonPreferences):
## TOOL_eraser_brush.addon_keymaps # has a checkbox in ## TOOL_eraser_brush.addon_keymaps # has a checkbox in
prev_key_category = '' prev_key_category = ''
kmi_see_list = []
for kms in [ for kms in [
OP_keyframe_jump.addon_keymaps, OP_keyframe_jump.addon_keymaps,
OP_copy_paste.addon_keymaps, OP_copy_paste.addon_keymaps,
OP_breakdowner.breakdowner_addon_keymaps, OP_breakdowner.addon_keymaps,
OP_key_duplicate_send.addon_keymaps, OP_key_duplicate_send.addon_keymaps,
OP_layer_picker.addon_keymaps, OP_layer_picker.addon_keymaps,
OP_material_picker.addon_keymaps, OP_material_picker.addon_keymaps,
OP_layer_nav.addon_keymaps,
# OP_layer_manager.addon_keymaps, # Do not display, wm.call_panel call panel ops mixed with natives shortcut (F2)
]: ]:
ct = 0 ct = 0
@ -644,6 +693,7 @@ def register():
OP_eraser_brush.register() OP_eraser_brush.register()
OP_material_picker.register() OP_material_picker.register()
OP_layer_picker.register() OP_layer_picker.register()
OP_layer_nav.register()
TOOL_eraser_brush.register() TOOL_eraser_brush.register()
handler_draw_cam.register() handler_draw_cam.register()
UI_tools.register() UI_tools.register()
@ -670,6 +720,7 @@ def unregister():
UI_tools.unregister() UI_tools.unregister()
handler_draw_cam.unregister() handler_draw_cam.unregister()
TOOL_eraser_brush.unregister() TOOL_eraser_brush.unregister()
OP_layer_nav.unregister()
OP_layer_picker.unregister() OP_layer_picker.unregister()
OP_material_picker.unregister() OP_material_picker.unregister()
OP_eraser_brush.unregister() OP_eraser_brush.unregister()

View File

@ -8,6 +8,8 @@ def register_keymaps():
# km = addon.keymaps.new(name = "3D View", space_type = "VIEW_3D")# in 3D context # 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 # km = addon.keymaps.new(name = "Window", space_type = "EMPTY")# from everywhere
## Sculpt mode toggles
km = addon.keymaps.new(name = "Grease Pencil Stroke Sculpt Mode", space_type = "EMPTY", region_type='WINDOW') 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') kmi = km.keymap_items.new('wm.context_toggle', type='ONE', value='PRESS')
@ -22,6 +24,12 @@ def register_keymaps():
kmi.properties.data_path='scene.tool_settings.use_gpencil_select_mask_segment' kmi.properties.data_path='scene.tool_settings.use_gpencil_select_mask_segment'
addon_keymaps.append((km, kmi)) addon_keymaps.append((km, kmi))
## T temp cutter (need disabling of native T shortcut, maybe expose a button to set the shortcut as user ?)
# km = addon.keymaps.new(name = "Grease Pencil", space_type = "EMPTY")
# kmi = km.keymap_items.new('gpencil.stroke_cutter', type='LEFTMOUSE', value='PRESS', key_modifier='T')
# kmi.properties.flat_caps=False
# addon_keymaps.append((km, kmi))
def unregister_keymaps(): def unregister_keymaps():
for km, kmi in addon_keymaps: for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi) km.keymap_items.remove(kmi)

View File

@ -30,19 +30,14 @@ def set_matrix(gp_frame,mat):
# get view vector location (the 2 methods work fine) # get view vector location (the 2 methods work fine)
def get_view_origin_position(): def get_view_origin_position():
#method 1 ## method 1
# from bpy_extras import view3d_utils # from bpy_extras import view3d_utils
# region = bpy.context.region # region = bpy.context.region
# rv3d = bpy.context.region_data # rv3d = bpy.context.region_data
# view_loc = view3d_utils.region_2d_to_origin_3d(region, rv3d, (region.width/2.0, region.height/2.0)) # view_loc = view3d_utils.region_2d_to_origin_3d(region, rv3d, (region.width/2.0, region.height/2.0))
# print("view_loc1", view_loc)#Dbg ## method 2
#method 2
r3d = bpy.context.space_data.region_3d r3d = bpy.context.space_data.region_3d
view_loc2 = r3d.view_matrix.inverted().translation view_loc2 = r3d.view_matrix.inverted().translation
# print("view_loc2", view_loc2)#Dbg
# if view_loc != view_loc2: print('Might be an error when finding view coordinate')
return view_loc2 return view_loc2
def location_to_region(worldcoords): def location_to_region(worldcoords):
@ -76,6 +71,10 @@ def object_derived_get(ob, scene):
return ob_matrix_pairs return ob_matrix_pairs
# -----------------
### Bmesh
# -----------------
def link_vert(v,ordered_vert) : def link_vert(v,ordered_vert) :
for e in v.link_edges : for e in v.link_edges :
other_vert = e.other_vert(v) other_vert = e.other_vert(v)
@ -147,7 +146,11 @@ def gp_stroke_to_bmesh(strokes):
return strokes_info return strokes_info
def simple_draw_gp_stroke(pts,frame,width = 2, mat_id = 0): # -----------------
### GP Drawing
# -----------------
def simple_draw_gp_stroke(pts, frame, width = 2, mat_id = 0):
''' '''
draw basic stroke by passing list of point 3D coordinate draw basic stroke by passing list of point 3D coordinate
the frame to draw on and optional width parameter (default = 2) the frame to draw on and optional width parameter (default = 2)
@ -169,11 +172,11 @@ def simple_draw_gp_stroke(pts,frame,width = 2, mat_id = 0):
return stroke return stroke
## OLD - need update ## OLD - need update
def draw_gp_stroke(loop_info,frame,palette,width = 2) : def draw_gp_stroke(loop_info, frame, palette, width = 2) :
stroke = frame.strokes.new(palette) stroke = frame.strokes.new(palette)
stroke.line_width = width stroke.line_width = width
stroke.display_mode = '3DSPACE'# old->draw_mode stroke.display_mode = '3DSPACE'# old -> draw_mode
for i,info in enumerate(loop_info) : for i,info in enumerate(loop_info) :
stroke.points.add() stroke.points.add()
@ -894,13 +897,6 @@ def draw_kmi(km, kmi, layout):
### linking utility ### linking utility
# ----------------- # -----------------
"""
def link_objects_in_blend(filepath, obj_name, link=True):
'''Link an object by name from a file, if link is False, append instead of linking'''
with bpy.data.libraries.load(filepath, link=link) as (data_from, data_to):
data_to.objects = [o for o in data_from.objects if o == obj_name] # c.startswith(obj_name)
return data_to.objects
"""
def link_objects_in_blend(filepath, obj_name_list, link=True): def link_objects_in_blend(filepath, obj_name_list, link=True):
'''Link an object by name from a file, if link is False, append instead of linking''' '''Link an object by name from a file, if link is False, append instead of linking'''
if isinstance(obj_name_list, str): if isinstance(obj_name_list, str):
@ -922,4 +918,37 @@ def check_objects_in_blend(filepath, avoid_camera=True):
l = [o for o in data_from.objects if not any(x in o.lower() for x in ('camera', 'draw_cam', 'obj_cam'))] l = [o for o in data_from.objects if not any(x in o.lower() for x in ('camera', 'draw_cam', 'obj_cam'))]
else: else:
l = [o for o in data_from.objects] l = [o for o in data_from.objects]
return l return l
# -----------------
### props handling
# -----------------
def iterate_selector(zone, attr, state, info_attr = None, active_access='active'):
'''Iterate with given attribute'''
item_number = len(zone)
if item_number <= 1:
return
if getattr(zone, attr) == None:
print('no', attr, 'in', zone)
return
if state: # swap
info = None
bottom = None
new_index = getattr(zone, attr) + state
setattr(zone, attr, new_index % item_number)
if new_index == item_number:
bottom = 1 # bottom reached, cycle to first
elif new_index < 0:
bottom = -1 # up reached, cycle to last
if info_attr:
active_item = getattr(zone, active_access) # active by default
if active_item:
info = getattr(active_item, info_attr)
return info, bottom