[Bf-extensions-cvs] [e7a3d0d8] master: GPencil Tools: Layer navigator
Pullusb
noreply at git.blender.org
Mon Jan 23 20:52:15 CET 2023
Commit: e7a3d0d8482a7315ce77251f8410e9d8232be82c
Author: Pullusb
Date: Mon Jan 23 20:52:00 2023 +0100
Branches: master
https://developer.blender.org/rBAe7a3d0d8482a7315ce77251f8410e9d8232be82c
GPencil Tools: Layer navigator
Layer navigator: Continuous press on 'Y' shortcut override default layer menu popup with a new customized one designed for fullscreen work.
Popup include following features:
- Active layer always pop under under mouse when called
- Active layer is changed just by hovering over layers
- Opacity, hide, lock states can be tweaked in popup
- Passing lateral limits will fade inactive layers, useful to quickly inspect content.
- Layers can be reordered with simple drag'n'drop
- `+` button on the right add a new layer
- Layer box height/width, font size, and left-handed mode are accessible in addon preferences
- Extra shortcuts are enabled while layer navigator is up:
- `H` toggle all hide
- `L` toggle all lock
- `T` toggle auto-lock
Addon preferences UI now use one Tab per tool
===================================================================
M greasepencil_tools/__init__.py
A greasepencil_tools/layer_navigator.py
M greasepencil_tools/prefs.py
===================================================================
diff --git a/greasepencil_tools/__init__.py b/greasepencil_tools/__init__.py
index 25363439..fee75347 100644
--- a/greasepencil_tools/__init__.py
+++ b/greasepencil_tools/__init__.py
@@ -4,7 +4,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, 6, 2),
+"version": (1, 7, 9),
"blender": (3, 0, 0),
"location": "Sidebar > Grease Pencil > Grease Pencil Tools",
"warning": "",
@@ -19,38 +19,41 @@ from . import (prefs,
box_deform,
line_reshape,
rotate_canvas,
+ layer_navigator,
timeline_scrub,
draw_tools,
import_brush_pack,
ui_panels,
)
+modules = (
+ prefs,
+ box_deform,
+ line_reshape,
+ rotate_canvas,
+ layer_navigator,
+ timeline_scrub,
+ draw_tools,
+ import_brush_pack,
+ ui_panels,
+)
+
def register():
if bpy.app.background:
return
- prefs.register()
- timeline_scrub.register()
- box_deform.register()
- line_reshape.register()
- rotate_canvas.register()
- draw_tools.register()
- import_brush_pack.register()
- ui_panels.register()
-
- ## update tab name with update in pref file (passing addon_prefs)
+
+ for mod in modules:
+ mod.register()
+
+ ## Update tab name with update in pref file (passing addon_prefs)
prefs.update_panel(prefs.get_addon_prefs(), bpy.context)
def unregister():
if bpy.app.background:
return
- ui_panels.unregister()
- import_brush_pack.unregister()
- draw_tools.unregister()
- rotate_canvas.unregister()
- box_deform.unregister()
- line_reshape.unregister()
- timeline_scrub.unregister()
- prefs.unregister()
+
+ for mod in modules:
+ mod.unregister()
if __name__ == "__main__":
register()
diff --git a/greasepencil_tools/layer_navigator.py b/greasepencil_tools/layer_navigator.py
new file mode 100644
index 00000000..bb40034b
--- /dev/null
+++ b/greasepencil_tools/layer_navigator.py
@@ -0,0 +1,902 @@
+import bpy
+import blf, gpu
+import math
+from gpu_extras.batch import batch_for_shader
+from mathutils import Vector, Matrix
+from time import time
+from pathlib import Path
+
+from bpy.props import (BoolProperty, IntProperty)
+
+from .prefs import get_addon_prefs
+
+
+def rectangle_tris_from_coords(quad_list):
+ '''Get a list of Vector corner for a triangle
+ return a list of TRI for gpu drawing'''
+ return [
+ # tri 1
+ quad_list[0],
+ quad_list[1],
+ quad_list[2],
+ # tri 2
+ quad_list[0],
+ quad_list[3],
+ quad_list[2]
+ ]
+
+def round_to_ceil_even(f):
+ if (math.floor(f) % 2 == 0):
+ return math.floor(f)
+ else:
+ return math.floor(f) + 1
+
+def move_layer_to_index(l, idx):
+ a = [i for i, lay in enumerate(l.id_data.layers) if lay == l][0]
+ move = idx - a
+ if move == 0:
+ return
+ direction = 'UP' if move > 0 else 'DOWN'
+ for _i in range(abs(move)):
+ l.id_data.layers.move(l, direction)
+
+def get_reduced_area_coord(context):
+ w, h = context.region.width, context.region.height
+
+ ## minus tool leftbar + sidebar right
+ regs = context.area.regions
+ toolbar = regs[2]
+ sidebar = regs[3]
+ header = regs[0]
+ tool_header = regs[1]
+ up_margin = down_margin = 0
+ if tool_header.alignment == 'TOP':
+ up_margin += tool_header.height
+ else:
+ down_margin += tool_header.height
+
+ ## set corner values
+ left_down = (toolbar.width, down_margin+2)
+ right_down = (w - sidebar.width, down_margin+2)
+ left_up = (toolbar.width, h - up_margin-1)
+ right_up = (w - sidebar.width, h - up_margin-1)
+ return left_down, right_down, left_up, right_up
+
+def draw_callback_px(self, context):
+ if context.area != self.current_area:
+ return
+ font_id = 0
+
+ ## timer for debug purposes
+ # blf.position(font_id, 15, 30, 0)
+ # blf.size(font_id, 20, 72)
+ # blf.draw(font_id, "Time " + self.text)
+
+ shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR') # initiate shader
+ gpu.state.blend_set('ALPHA')
+ gpu.state.line_width_set(1.0)
+
+ shader.bind()
+
+ ## draw one background at once
+ # shader.uniform_float("color", self.bg_color) # (1.0, 1.0, 1.0, 1.0)
+ # self.batch_bg.draw(shader)
+
+ ## locked layer (individual rectangle)
+ rects = []
+ lock_rects = []
+ opacitys = []
+ opacity_bars = []
+ active_case = []
+ active_width = float(round_to_ceil_even(4.0 * context.preferences.system.ui_scale))
+
+ ## tex icon store
+ icons = {'locked':[],'unlocked':[], 'hide_off':[], 'hide_on':[]}
+
+ for i, l in enumerate(self.gpl):
+ ## Rectangle coords CW from bottom-left corner
+
+ corner = Vector((self.left, self.bottom + self.px_h * i))
+ if i == self.ui_idx:
+ # With LINE_STRIP: Repeat first coordinate to close square with line_strip shader
+ # active_case = [v + corner for v in self.case] + [self.case[0] + corner]
+
+ ## With LINES: width offset to avoid jaggy corner
+ # Convert single corners point to flattened line vector pairs
+ active_case = [v + corner for v in self.case]
+ flattened_line_pairs = []
+ for i in range(len(active_case)):
+ flattened_line_pairs += [active_case[i], active_case[(i+1) % len(active_case)]]
+
+ # Build offset table
+ px_offset = int(active_width / 2)
+ case_px_offsets = [
+ Vector((0, -px_offset)), Vector((0, px_offset)),
+ Vector((-px_offset, 0)), Vector((px_offset, 0)),
+ Vector((0, px_offset)), Vector((0, -px_offset)),
+ Vector((px_offset, 0)), Vector((-px_offset, 0)),
+ ]
+
+ # Apply offset to line tips
+ active_case = [v + offset for v, offset in zip(flattened_line_pairs, case_px_offsets)]
+
+
+ lock_coord = corner + Vector((self.px_w - self.icons_margin_a, self.mid_height - int(self.icon_size / 2)))
+
+ hide_coord = corner + Vector((self.px_w - self.icons_margin_b, self.mid_height - int(self.icon_size / 2)))
+
+
+ if l.lock:
+ lock_rects += rectangle_tris_from_coords(
+ [v + corner for v in self.case]
+ )
+ icons['locked'].append([v + lock_coord for v in self.icon_tex_coord])
+ else:
+ rects += rectangle_tris_from_coords(
+ [v + corner for v in self.case]
+ )
+ icons['unlocked'].append([v + lock_coord for v in self.icon_tex_coord])
+
+
+ if l.hide:
+ icons['hide_on'].append([v + hide_coord for v in self.icon_tex_coord])
+ else:
+ icons['hide_off'].append([v + hide_coord for v in self.icon_tex_coord])
+
+
+ ## opacity sliders background
+ opacity_bars += rectangle_tris_from_coords(
+ [corner + v for v in self.opacity_slider]
+ )
+ ## opacity sliders
+ if l.opacity:
+ opacitys += rectangle_tris_from_coords(
+ [corner + v for v in self.opacity_slider[:2]]
+ + [corner + Vector((int(v[0] * l.opacity), v[1])) for v in self.opacity_slider[2:]]
+ )
+
+ ### --- Trace squares
+ ## individual unlocked squares
+ shader.uniform_float("color", self.bg_color)
+ batch_squares = batch_for_shader(shader, 'TRIS', {"pos": rects})
+ batch_squares.draw(shader)
+
+ ## locked squares
+ shader.uniform_float("color", self.lock_color)
+ batch_lock = batch_for_shader(shader, 'TRIS', {"pos": lock_rects})
+ batch_lock.draw(shader)
+
+ ## bg_full_bar
+ shader.uniform_float("color", self.opacity_bar_color)
+ batch_lock = batch_for_shader(shader, 'TRIS', {"pos": opacity_bars})
+ batch_lock.draw(shader)
+
+ ## opacity sliders
+ shader.uniform_float("color", self.opacity_color)
+ batch_lock = batch_for_shader(shader, 'TRIS', {"pos": opacitys})
+ batch_lock.draw(shader)
+
+ ### --- Trace Lines
+ gpu.state.line_width_set(2.0)
+
+ ## line color (static)
+ shader.uniform_float("color", self.lines_color)
+ self.batch_lines.draw(shader)
+
+ ## "Plus" lines
+ if self.gpl.active_index == 0:
+ plus_lines = self.plus_lines[:8]
+ else:
+ plus_lines = self.plus_lines[self.gpl.active_index * 4 + 4:self.gpl.active_index * 4 + 8]
+ batch_plus = batch_for_shader(
+ shader, 'LINES', {"pos": plus_lines})
+ batch_plus.draw(shader)
+
+ ## Loop draw tex icons
+ for icon_name, coord_list in icons.items():
+ texture = gpu.texture.from_image(self.icon_tex[icon_name])
+ for coords in coord_list:
+ shader_tex = gpu.shader.from_builtin('2D_IMAGE')
+ batch_icons = batch_for_shader(
+ shader_tex, 'TRI_FAN',
+ {
+ "pos": coords,
+ "texCoord": ((0, 0), (1, 0), (1, 1), (0, 1)),
+ },
+ )
+ shader_tex.bind()
+ shader_tex.uniform_sampler("image", texture)
+ batch_icons.draw(shader_tex)
+
+ ## Highlight active layer
+ if active_case:
+ gpu.state.line_width_set(active_width)
+ shader.uniform_float("color", self.active_layer_color)
+ # batch_active = batch_for_shader(shader, 'LINE_STRIP', {"pos": active_case})
+ batch_active = batch_for_shader(shader, 'LINES', {"pos": active_case})
+ batch_active.draw(shader)
+
+ gpu.state.line_width_set(1.0)
+ gpu.state.blend_set('NONE')
+
+
+ ### --- Texts
+ for i, l in enumerate(self.gpl):
+ ## add color underneath active name
+ # if i == self.ui_idx:
+ # ## color = self.active_layer_color # Color active name
+ # blf.position(font_id, self.text_x+1, self.text_pos[i]-1, 0)
+ # blf.size(font_id, self.text_size, 72)
+ # blf.color(font_id, *self.act
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list