[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