[Bf-extensions-cvs] [76fba3f8] master: GPencil Tools: Add viewport timeline scrub feature
Pullusb
noreply at git.blender.org
Sun Jan 24 18:36:52 CET 2021
Commit: 76fba3f84b6fdcc350d232eb740c0cd72ac9ffb7
Author: Pullusb
Date: Sun Jan 24 18:36:37 2021 +0100
Branches: master
https://developer.blender.org/rBA76fba3f84b6fdcc350d232eb740c0cd72ac9ffb7
GPencil Tools: Add viewport timeline scrub feature
Add timeline scrubbing from the standalone add-on : https://github.com/Pullusb/viewport_timeline_scrub
This bind a shortcut to move in timeline directly from viewport, VSE and movie clip editors.
Display keyframes and snap using `Ctrl` key.
Propagate the chosen shortcut to timeline editors.
Shortcut, behavior and overlays can be customized in addon-preferences.
===================================================================
M greasepencil_tools/__init__.py
M greasepencil_tools/prefs.py
A greasepencil_tools/timeline_scrub.py
===================================================================
diff --git a/greasepencil_tools/__init__.py b/greasepencil_tools/__init__.py
index 02e93c61..abc7a033 100644
--- a/greasepencil_tools/__init__.py
+++ b/greasepencil_tools/__init__.py
@@ -21,7 +21,7 @@ bl_info = {
"name": "Grease Pencil Tools",
"description": "Extra tools for Grease Pencil",
"author": "Samuel Bernou, Antonio Vazquez, Daniel Martinez Lara, Matias Mendiola",
-"version": (1, 1, 6),
+"version": (1, 2, 0),
"blender": (2, 91, 0),
"location": "Sidebar > Grease Pencil > Grease Pencil Tools",
"warning": "",
@@ -36,12 +36,14 @@ from . import (prefs,
box_deform,
line_reshape,
rotate_canvas,
+ timeline_scrub,
import_brush_pack,
ui_panels,
)
def register():
prefs.register()
+ timeline_scrub.register()
box_deform.register()
line_reshape.register()
rotate_canvas.register()
@@ -57,6 +59,7 @@ def unregister():
rotate_canvas.unregister()
box_deform.unregister()
line_reshape.unregister()
+ timeline_scrub.unregister()
prefs.unregister()
if __name__ == "__main__":
diff --git a/greasepencil_tools/prefs.py b/greasepencil_tools/prefs.py
index 1475e95c..69b92780 100644
--- a/greasepencil_tools/prefs.py
+++ b/greasepencil_tools/prefs.py
@@ -22,6 +22,7 @@ from bpy.props import (
BoolProperty,
EnumProperty,
StringProperty,
+ PointerProperty,
# IntProperty,
)
@@ -33,6 +34,8 @@ def get_addon_prefs():
addon_prefs = bpy.context.preferences.addons[addon_name].preferences
return (addon_prefs)
+from .timeline_scrub import GPTS_timeline_settings, draw_ts_pref
+
## Addons Preferences Update Panel
def update_panel(self, context):
try:
@@ -48,9 +51,11 @@ def auto_rebind(self, context):
register_keymaps()
class GreasePencilAddonPrefs(bpy.types.AddonPreferences):
- bl_idname = os.path.splitext(__name__)[0]#'greasepencil-addon' ... __package__ ?
+ bl_idname = os.path.splitext(__name__)[0] #'greasepencil-addon' ... __package__ ?
# bl_idname = __name__
+ ts: PointerProperty(type=GPTS_timeline_settings)
+
category : StringProperty(
name="Category",
description="Choose a name for the category of the panel",
@@ -127,6 +132,7 @@ class GreasePencilAddonPrefs(bpy.types.AddonPreferences):
update=auto_rebind)
def draw(self, context):
+ prefs = get_addon_prefs()
layout = self.layout
# layout.use_property_split = True
row= layout.row(align=True)
@@ -176,6 +182,9 @@ class GreasePencilAddonPrefs(bpy.types.AddonPreferences):
box.label(text="view3d.rotate_canvas")
box.prop(self, 'canvas_use_hud')
+ ## SCRUB TIMELINE
+ box = layout.box()
+ draw_ts_pref(prefs.ts, box)
if self.pref_tabs == 'TUTO':
@@ -237,6 +246,7 @@ def unregister_keymaps():
### REGISTER ---
def register():
+ bpy.utils.register_class(GPTS_timeline_settings)
bpy.utils.register_class(GreasePencilAddonPrefs)
# Force box deform running to false
bpy.context.preferences.addons[os.path.splitext(__name__)[0]].preferences.boxdeform_running = False
@@ -245,3 +255,4 @@ def register():
def unregister():
unregister_keymaps()
bpy.utils.unregister_class(GreasePencilAddonPrefs)
+ bpy.utils.unregister_class(GPTS_timeline_settings)
\ No newline at end of file
diff --git a/greasepencil_tools/timeline_scrub.py b/greasepencil_tools/timeline_scrub.py
new file mode 100644
index 00000000..7a783e0b
--- /dev/null
+++ b/greasepencil_tools/timeline_scrub.py
@@ -0,0 +1,807 @@
+# ##### 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 viewport_timeline_scrub standalone addon - Samuel Bernou'''
+
+from .prefs import get_addon_prefs
+
+import numpy as np
+from time import time
+import bpy
+import gpu
+import bgl
+import blf
+from gpu_extras.batch import batch_for_shader
+
+from bpy.props import (BoolProperty,
+ StringProperty,
+ IntProperty,
+ FloatVectorProperty,
+ IntProperty,
+ PointerProperty,
+ EnumProperty)
+
+""" bl_info = {
+ "name": "Viewport Scrub Timeline",
+ "description": "Scrub on timeline from viewport and snap to nearest keyframe",
+ "author": "Samuel Bernou",
+ "version": (0, 7, 5),
+ "blender": (2, 91, 0),
+ "location": "View3D > shortcut key chosen in addon prefs",
+ "warning": "",
+ "doc_url": "https://github.com/Pullusb/scrub_timeline",
+ "category": "Object"}
+ """
+
+def nearest(array, value):
+ '''
+ Get a numpy array and a target value
+ Return closest val found in array to passed value
+ '''
+ idx = (np.abs(array - value)).argmin()
+ return array[idx]
+
+
+def draw_callback_px(self, context):
+ '''Draw callback use by modal to draw in viewport'''
+ if context.area != self.current_area:
+ return
+ ## lines and shaders
+ # 50% alpha, 2 pixel width line
+
+ # text
+ font_id = 0
+
+ shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR') # initiate shader
+ bgl.glEnable(bgl.GL_BLEND)
+ bgl.glLineWidth(1)
+
+ # - # Draw HUD
+ if self.use_hud_time_line:
+ shader.bind()
+ shader.uniform_float("color", self.color_timeline)
+ self.batch_timeline.draw(shader)
+
+ # - # Display keyframes
+ if self.use_hud_keyframes:
+ if self.keyframe_aspect == 'LINE':
+ bgl.glLineWidth(3)
+ shader.bind()
+ shader.uniform_float("color", self.color_timeline)
+ self.batch_keyframes.draw(shader)
+ else:
+ # - # Display keyframe as diamonds
+ bgl.glLineWidth(1)
+ shader.bind()
+ shader.uniform_float("color", self.color_timeline)
+ # shader.uniform_float("color", list(self.color_timeline[:3]) + [1]) # timeline color full opacity
+ # shader.uniform_float("color", (0.8, 0.8, 0.8, 0.8)) # grey
+ # shader.uniform_float("color", (0.9, 0.69, 0.027, 1.0)) # yellow-ish
+ # shader.uniform_float("color",(1.0, 0.515, 0.033, 1.0)) # orange 'selected keyframe'
+ self.batch_keyframes.draw(shader)
+
+ # - # Display init frame text (under playhead)
+ # if self.use_hud_frame_init: # propertie not existing currently
+ # blf.position(font_id, self.init_mouse_x,
+ # self.init_mouse_y - (60 *self.ui_scale), 0)
+ # blf.size(font_id, 16, self.dpi)
+ # blf.color(font_id, *self.color_timeline)
+ # blf.draw(font_id, f'{self.init_frame:.0f}')
+
+ # - # Show current frame line
+ bgl.glLineWidth(1)
+ if self.use_hud_playhead:
+ # -# old full height playhead
+ # playhead = [(self.cursor_x, 0), (self.cursor_x, context.area.height)]
+ playhead = [(self.cursor_x, self.my + self.playhead_size/2),
+ (self.cursor_x, self.my - self.playhead_size/2)]
+ batch = batch_for_shader(shader, 'LINES', {"pos": playhead})
+ shader.bind()
+ shader.uniform_float("color", self.color_playhead)
+ batch.draw(shader)
+
+ # restore opengl defaults
+ bgl.glDisable(bgl.GL_BLEND)
+
+ # - # Display current frame text
+ blf.color(font_id, *self.color_text)
+ if self.use_hud_frame_current:
+ blf.position(font_id, self.mouse[0]+10, self.mouse[1]+10, 0)
+ # Id, Point size of the font, dots per inch value to use for drawing.
+ blf.size(font_id, 30, self.dpi) # 72
+ blf.draw(font_id, f'{self.new_frame:.0f}')
+
+ # - # Display frame offset text
+ if self.use_hud_frame_offset:
+ blf.position(font_id, self.mouse[0]+10,
+ self.mouse[1]+(40*self.ui_scale), 0)
+ blf.size(font_id, 16, self.dpi)
+ # blf.color(font_id, *self.color_text)
+ sign = '+' if self.offset > 0 else ''
+ blf.draw(font_id, f'{sign}{self.offset:.0f}')
+
+
+class GPTS_OT_time_scrub(bpy.types.Operator):
+ bl_idname = "animation.time_scrub"
+ bl_label = "Time scrub"
+ bl_description = "Quick time scrubbing with a shortcut"
+ bl_options = {"REGISTER", "INTERNAL", "UNDO"}
+
+ @classmethod
+ def poll(cls, context):
+ return context.space_data.type in ('VIEW_3D', 'SEQUENCE_EDITOR', 'CLIP_EDITOR')
+
+ def invoke(self, context, event):
+ prefs = get_addon_prefs().ts
+ # Gpencil contexts : ('PAINT_GPENCIL', 'EDIT_GPENCIL')
+ # if context.space_data.type != 'VIEW_3D':
+ # self.report({'WARNING'}, "Work only in Viewport")
+ # return {'CANCELLED'}
+
+ self.current_area = context.area
+ self.key = prefs.keycode
+ self.evaluate_gp_obj_key = prefs.evaluate_gp_obj_key
+
+ self.dpi = context.preferences.system.dpi
+ self.ui_scale = context.preferences.system.ui_scale
+ # hud prefs
+ self.color_timeline = prefs.color_timeline
+ self.color_playhead = prefs.color_playhead
+ self.color_text = prefs.color_playhead
+ self.use_hud_time_line = prefs.use_hud_time_line
+ self.use_hud_keyframes = prefs.use_hud_keyframes
+ self.keyframe_aspect = prefs.keyframe_aspect
+ self.use_hud_playhead = prefs.use_hud_playhead
+ self.use_hud_frame_current = prefs.use_hud_frame
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list