[Bf-extensions-cvs] [822a1da4] master: GPencil Tools: Add rolling timeline
Pullusb
noreply at git.blender.org
Mon Mar 15 01:09:54 CET 2021
Commit: 822a1da41c31537b1f864898d5ab901c321830d5
Author: Pullusb
Date: Mon Mar 15 01:09:22 2021 +0100
Branches: master
https://developer.blender.org/rBA822a1da41c31537b1f864898d5ab901c321830d5
GPencil Tools: Add rolling timeline
Rolling mode: Introduce a new alternative timeline (as an option in addon preferences, disabled by default)
Display all keys without timegap (discard timing informations).
Allow to quickly roll/flip over keyframes.
===================================================================
M greasepencil_tools/__init__.py
M greasepencil_tools/timeline_scrub.py
===================================================================
diff --git a/greasepencil_tools/__init__.py b/greasepencil_tools/__init__.py
index de5bf06c..fa8e97c1 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, 3, 4),
+"version": (1, 4, 0),
"blender": (2, 91, 0),
"location": "Sidebar > Grease Pencil > Grease Pencil Tools",
"warning": "",
diff --git a/greasepencil_tools/timeline_scrub.py b/greasepencil_tools/timeline_scrub.py
index d742b594..3f69ebb9 100644
--- a/greasepencil_tools/timeline_scrub.py
+++ b/greasepencil_tools/timeline_scrub.py
@@ -123,6 +123,7 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
self.key = prefs.keycode
self.evaluate_gp_obj_key = prefs.evaluate_gp_obj_key
self.always_snap = prefs.always_snap
+ self.rolling_mode = prefs.rolling_mode
self.dpi = context.preferences.system.dpi
self.ui_scale = context.preferences.system.ui_scale
@@ -146,7 +147,7 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
self.init_mouse_x = self.cursor_x = event.mouse_region_x
# self.init_mouse_y = event.mouse_region_y # only to display init frame text
- self.init_frame = self.new_frame = context.scene.frame_current
+ self.cancel_frame = self.init_frame = self.new_frame = context.scene.frame_current
self.lock_range = context.scene.lock_frame_selection_to_range
if context.scene.use_preview_range:
self.f_start = context.scene.frame_preview_start
@@ -195,11 +196,28 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
if not ob or not self.pos:
# Disable inverted behavior if no frame to snap
self.always_snap = False
+ if self.rolling_mode:
+ self.report({'WARNING'}, 'No Keys to flip on')
+ return {'CANCELLED'}
+
+ if self.rolling_mode:
+ # sorted and casted to int list since it's going to work with indexes
+ self.pos = sorted([int(f) for f in self.pos])
+ # find and make current frame the "starting" frame (force snap)
+ active_pos = [i for i, num in enumerate(self.pos) if num <= self.init_frame]
+ if active_pos:
+ self.init_index = active_pos[-1]
+ self.init_frame = self.new_frame = self.pos[self.init_index]
+ else:
+ self.init_index = 0
+ self.init_frame = self.new_frame = self.pos[0]
+
+ # del active_pos
+ self.index_limit = len(self.pos) - 1
# Also snap on play bounds (sliced off for keyframe display)
self.pos += [self.f_start, self.f_end]
-
# Disable Onion skin
self.active_space_data = context.space_data
self.onion_skin = None
@@ -241,43 +259,44 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
self.hud_lines = []
- # frame marks
- for x in hud_pos_x:
- self.hud_lines.append((x, my - (frame_height/2)))
- self.hud_lines.append((x, my + (frame_height/2)))
+ if not self.rolling_mode:
+ # frame marks
+ for x in hud_pos_x:
+ self.hud_lines.append((x, my - (frame_height/2)))
+ self.hud_lines.append((x, my + (frame_height/2)))
# init frame mark
self.hud_lines += [(self.init_mouse_x, my - (init_height/2)),
(self.init_mouse_x, my + (init_height/2))]
- # Add start/end boundary bracket to HUD
-
- start_x = self.init_mouse_x + \
- (self.f_start - self.init_frame) * self.px_step
- end_x = self.init_mouse_x + \
- (self.f_end - self.init_frame) * self.px_step
-
- # start
- up = (start_x, my - (bound_h/2))
- dn = (start_x, my + (bound_h/2))
- self.hud_lines.append(up)
- self.hud_lines.append(dn)
-
- self.hud_lines.append(up)
- self.hud_lines.append((up[0] + bound_bracket_l, up[1]))
- self.hud_lines.append(dn)
- self.hud_lines.append((dn[0] + bound_bracket_l, dn[1]))
-
- # end
- up = (end_x, my - (bound_h/2))
- dn = (end_x, my + (bound_h/2))
- self.hud_lines.append(up)
- self.hud_lines.append(dn)
-
- self.hud_lines.append(up)
- self.hud_lines.append((up[0] - bound_bracket_l, up[1]))
- self.hud_lines.append(dn)
- self.hud_lines.append((dn[0] - bound_bracket_l, dn[1]))
+ if not self.rolling_mode:
+ # Add start/end boundary bracket to HUD
+ start_x = self.init_mouse_x + \
+ (self.f_start - self.init_frame) * self.px_step
+ end_x = self.init_mouse_x + \
+ (self.f_end - self.init_frame) * self.px_step
+
+ # start
+ up = (start_x, my - (bound_h/2))
+ dn = (start_x, my + (bound_h/2))
+ self.hud_lines.append(up)
+ self.hud_lines.append(dn)
+
+ self.hud_lines.append(up)
+ self.hud_lines.append((up[0] + bound_bracket_l, up[1]))
+ self.hud_lines.append(dn)
+ self.hud_lines.append((dn[0] + bound_bracket_l, dn[1]))
+
+ # end
+ up = (end_x, my - (bound_h/2))
+ dn = (end_x, my + (bound_h/2))
+ self.hud_lines.append(up)
+ self.hud_lines.append(dn)
+
+ self.hud_lines.append(up)
+ self.hud_lines.append((up[0] - bound_bracket_l, up[1]))
+ self.hud_lines.append(dn)
+ self.hud_lines.append((dn[0] - bound_bracket_l, dn[1]))
# Horizontal line
self.hud_lines += [(0, my), (width, my)]
@@ -286,16 +305,24 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR') # initiate shader
self.batch_timeline = batch_for_shader(
shader, 'LINES', {"pos": self.hud_lines})
+
+ if self.rolling_mode:
+ current_id = self.pos.index(self.new_frame)
+ # Add init_frame to "cancel" it in later UI code
+ ui_key_pos = [i - current_id + self.init_frame for i, _f in enumerate(self.pos[:-2])]
+ else:
+ ui_key_pos = self.pos[:-2]
+
# keyframe display
if self.keyframe_aspect == 'LINE':
key_lines = []
# Slice off position of start/end frame added last (in list for snapping)
- for i in self.pos[:-2]:
+ for i in ui_key_pos:
key_lines.append(
(self.init_mouse_x + ((i-self.init_frame) * self.px_step), my - (key_height/2)))
key_lines.append(
- (self.init_mouse_x + ((i-self.init_frame)*self.px_step), my + (key_height/2)))
+ (self.init_mouse_x + ((i-self.init_frame) * self.px_step), my + (key_height/2)))
self.batch_keyframes = batch_for_shader(
shader, 'LINES', {"pos": key_lines})
@@ -309,7 +336,7 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
shaped_key = []
indices = []
idx_offset = 0
- for i in self.pos[:-2]:
+ for i in ui_key_pos:
center = self.init_mouse_x + ((i-self.init_frame)*self.px_step)
if self.keyframe_aspect == 'DIAMOND':
# +1 on x is to correct pixel alignement
@@ -339,6 +366,8 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
# convert frame list to array for numpy snap utility
self.pos = np.asarray(self.pos)
+ if self.rolling_mode:
+ context.scene.frame_current = self.new_frame
args = (self, context)
self.viewtype = None
@@ -383,42 +412,52 @@ class GPTS_OT_time_scrub(bpy.types.Operator):
self.offset = int(px_offset / self.px_step)
self.new_frame = self.init_frame + self.offset
- mod_snap = False
- if self.snap_ctrl and event.ctrl:
- mod_snap = True
- if self.snap_shift and event.shift:
- mod_snap = True
- if self.snap_alt and event.alt:
- mod_snap = True
-
- ## Snapping
- if self.always_snap:
- # inverted snapping behavior
- if not self.snap_on and not mod_snap:
- self.new_frame = nearest(self.pos, self.new_frame)
- else:
- if self.snap_on or mod_snap:
- self.new_frame = nearest(self.pos, self.new_frame)
+ if self.rolling_mode:
+ # Frame Flipping mode (equidistant scrub snap)
+ self.index = self.init_index + self.offset
+ # clamp to possible index range
+ self.index = min(max(self.index, 0), self.index_limit)
+ self.new_frame = self.pos[self.index]
+ context.scene.frame_current = self.new_frame
+ self.cursor_x = self.init_mouse_x + (self.offset * self.px_step)
- # frame range restriction
- if self.lock_range:
- if self.new_frame < self.f_start:
- self.new_frame = self.f_start
- elif self.new_frame > self.f_end:
- self.new_frame = self.f_end
-
- # context.scene.frame_set(self.new_frame)
- context.scene.frame_current = self.new_frame
-
- # - recalculate offset to snap cursor to frame
- self.offset = self.new_frame - self.init_frame
-
- # - calculate cursor pixel position from frame offset
- self.cursor_x = self.init_mouse_x + (self.offset * self.px_step)
+ else:
+ mod_snap = False
+ if self.snap_ctrl and event.ctrl:
+ mod_snap = True
+ if self.snap_shift and event.shift:
+ mod_snap = True
+ if self.snap_alt and event.alt:
+ mod_snap = True
+
+ ## Snapping
+ if self.al
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list