Grease Pencil: Edit Mode Pen Tool

This adds the `Pen` tool to Grease Pencil Edit Mode.

With the pen tool you can:
- Extrude points by `Left Click`.
- Move the handles by dragging the mouse.
- Snap handles to 45 degree increments with `Shift`.
- Cycle through the handle types by `Double Clicking`.
- Add new point on segments by `Ctrl Clicking`.
- Remove existing point by `Ctrl Clicking`.
- Close a curve by clicking on one end while having the other selected.
- Move existing segment by clicking and dragging on the edge.
- Move points by clicking and dragging the mouse.

Some changes have been made compared to the legacy
curve object's pen tool:
- `Angle locking` with `Alt` was replaced with `Angle Snapping`
   using `Shift`. This was done to match the behavior of Grease Pencil
   primitive tools.
- `Move Entire Point` was changed from the `Space` key to `Alt`. This
   was done because some laptops can't move the mouse while
  `Space` is held.
- `Link Handles` and `Free Align Toggle` were not implemented.
- `Toggle Vector` and `Close Spline Method` were removed.
- `Close Spline` was removed and set to always be true.
- `Extrude Handle` type was removed as a option and was replaced
   by the `shift` modifier key when clicking.
- Newly created points are placed on the drawing plane, instead of
  the view plane.

When a new curve is created, the material will be the active material
and the radius will be set from the `radius` property.

Note: This tool is added to edit mode because it uses handle selection
and bézier overlays which currently don't exist in draw mode.
A future PR will implement a draw mode version.

Pull Request: https://projects.blender.org/blender/blender/pulls/142646
This commit is contained in:
Casey Bianco-Davis 2025-08-15 18:17:09 +02:00 • committed by Falk David
parent 3dc73a3fda
commit a767671c56
7 changed files with 1563 additions and 0 deletions

View file

@ -108,6 +108,7 @@ _km_hierarchy = [
]),
('Primitive Tool Modal Map', 'EMPTY', 'WINDOW', []),
('Pen Tool Modal Map', 'EMPTY', 'WINDOW', []),
('Knife Tool Modal Map', 'EMPTY', 'WINDOW', []),
('Custom Normals Modal Map', 'EMPTY', 'WINDOW', []),
('Bevel Modal Map', 'EMPTY', 'WINDOW', []),

View file

@ -8328,6 +8328,53 @@ def km_grease_pencil_interpolate_tool_modal_map(_params):
return keymap
def km_grease_pencil_pen_tool_modal_map(_params):
items = []
keymap = (
"Pen Tool Modal Map",
{"space_type": 'EMPTY', "region_type": 'WINDOW', "modal": True},
{"items": items},
)
items.extend([
("MOVE_HANDLE", {"type": 'LEFT_CTRL', "value": 'ANY', "any": True}, None),
("MOVE_ENTIRE", {"type": 'LEFT_ALT', "value": 'ANY', "any": True}, None),
("SNAP_ANGLE", {"type": 'LEFT_SHIFT', "value": 'ANY', "any": True}, None),
])
return keymap
def km_3d_view_tool_edit_grease_pencil_pen(params):
return (
"3D View Tool: Edit Grease Pencil, Pen",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
("grease_pencil.pen", {"type": params.tool_mouse, "value": 'PRESS'},
{"properties": [
("extrude_point", True),
("move_segment", True),
("select_point", True),
("move_point", True),
("extrude_handle", "VECTOR"),
]}),
("grease_pencil.pen", {"type": params.tool_mouse, "value": 'PRESS', "shift": True},
{"properties": [
("extrude_point", True),
("move_segment", True),
("select_point", True),
("move_point", True),
("extrude_handle", "AUTO"),
]}),
("grease_pencil.pen", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
{"properties": [("insert_point", True), ("delete_point", True)]}),
("grease_pencil.pen", {"type": params.tool_mouse, "value": 'DOUBLE_CLICK'},
{"properties": [("cycle_handle_type", True)]}),
]},
)
# ------------------------------------------------------------------------------
# Grease Pencil: Texture Gradient Tool
@ -8648,6 +8695,7 @@ def generate_keymaps(params=None):
km_node_link_modal_map(params),
km_node_resize_modal_map(params),
km_grease_pencil_primitive_tool_modal_map(params),
km_grease_pencil_pen_tool_modal_map(params),
km_grease_pencil_fill_tool_modal_map(params),
km_grease_pencil_interpolate_tool_modal_map(params),
km_sequencer_slip_modal_map(params),
@ -8796,6 +8844,7 @@ def generate_keymaps(params=None):
km_sequencer_preview_tool_move(params),
km_sequencer_preview_tool_rotate(params),
km_sequencer_preview_tool_scale(params),
km_3d_view_tool_edit_grease_pencil_pen(params),
km_3d_view_tool_edit_grease_pencil_interpolate(params),
km_3d_view_tool_paint_grease_pencil_interpolate(params),
km_3d_view_tool_paint_grease_pencil_eyedropper(params),

View file

@ -2426,6 +2426,41 @@ class _defs_grease_pencil_edit:
keymap=(),
)
@ToolDef.from_fn
def pen():
def draw_settings(context, layout, tool):
props = tool.operator_properties("grease_pencil.pen")
layout.prop(props, "radius")
layout.separator()
tool_settings = context.tool_settings
sub = layout.row(align=True)
sub.prop_with_popover(
tool_settings,
"gpencil_stroke_placement_view3d",
text="",
panel="VIEW3D_PT_grease_pencil_origin",
)
sub = layout.row(align=True)
sub.active = tool_settings.gpencil_stroke_placement_view3d != 'SURFACE'
sub.prop_with_popover(
tool_settings.gpencil_sculpt,
"lock_axis",
text="",
panel="VIEW3D_PT_grease_pencil_lock",
)
return dict(
idname="builtin.pen",
label="Pen",
cursor='CROSSHAIR',
icon="ops.curve.pen",
widget=None,
keymap=(),
draw_settings=draw_settings,
)
class _defs_image_generic:
@ -3659,6 +3694,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
*_tools_transform,
None,
_defs_grease_pencil_edit.pen,
None,
_defs_edit_curve.curve_radius,
_defs_transform.bend,
(

View file

@ -29,6 +29,7 @@ set(SRC
intern/grease_pencil_merge.cc
intern/grease_pencil_modes.cc
intern/grease_pencil_ops.cc
intern/grease_pencil_pen.cc
intern/grease_pencil_primitive.cc
intern/grease_pencil_randomize.cc
intern/grease_pencil_select.cc

View file

@ -320,6 +320,7 @@ void ED_operatortypes_grease_pencil()
ED_operatortypes_grease_pencil_lineart();
ED_operatortypes_grease_pencil_trace();
ED_operatortypes_grease_pencil_bake_animation();
ED_operatortypes_grease_pencil_pen();
}
void ED_operatormacros_grease_pencil()
@ -370,6 +371,7 @@ void ED_keymap_grease_pencil(wmKeyConfig *keyconf)
keymap_grease_pencil_fill_tool(keyconf);
ED_primitivetool_modal_keymap(keyconf);
ED_pentool_modal_keymap(keyconf);
ED_filltool_modal_keymap(keyconf);
ED_interpolatetool_modal_keymap(keyconf);
}

File diff suppressed because it is too large Load diff

View file

@ -72,6 +72,7 @@ void ED_operatortypes_grease_pencil_edit();
void ED_operatortypes_grease_pencil_join();
void ED_operatortypes_grease_pencil_material();
void ED_operatortypes_grease_pencil_modes();
void ED_operatortypes_grease_pencil_pen();
void ED_operatortypes_grease_pencil_primitives();
void ED_operatortypes_grease_pencil_weight_paint();
void ED_operatortypes_grease_pencil_vertex_paint();
@ -84,6 +85,7 @@ void ED_keymap_grease_pencil(wmKeyConfig *keyconf);
void ED_primitivetool_modal_keymap(wmKeyConfig *keyconf);
void ED_filltool_modal_keymap(wmKeyConfig *keyconf);
void ED_interpolatetool_modal_keymap(wmKeyConfig *keyconf);
void ED_pentool_modal_keymap(wmKeyConfig *keyconf);
void GREASE_PENCIL_OT_stroke_trim(wmOperatorType *ot);