Blender V4.3
gpencil_data.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <algorithm>
12#include <cmath>
13#include <cstddef>
14#include <cstdio>
15#include <cstdlib>
16#include <cstring>
17
18#include "MEM_guardedalloc.h"
19
20#include "BLI_blenlib.h"
21#include "BLI_ghash.h"
22#include "BLI_math_geom.h"
23#include "BLI_math_matrix.h"
24#include "BLI_math_vector.h"
25#include "BLI_string_utils.hh"
26#include "BLI_utildefines.h"
27
28#include "BLT_translation.hh"
29
30#include "DNA_anim_types.h"
31#include "DNA_brush_types.h"
33#include "DNA_material_types.h"
34#include "DNA_meshdata_types.h"
35#include "DNA_object_types.h"
36#include "DNA_scene_types.h"
37#include "DNA_screen_types.h"
38#include "DNA_view3d_types.h"
39
40#include "BKE_anim_data.hh"
41#include "BKE_animsys.h"
42#include "BKE_brush.hh"
43#include "BKE_context.hh"
44#include "BKE_deform.hh"
45#include "BKE_fcurve_driver.h"
46#include "BKE_gpencil_legacy.h"
47#include "BKE_lib_id.hh"
48#include "BKE_main.hh"
49#include "BKE_material.h"
50#include "BKE_paint.hh"
51#include "BKE_report.hh"
52
53#include "UI_interface.hh"
54#include "UI_resources.hh"
55
56#include "WM_api.hh"
57#include "WM_types.hh"
58
59#include "RNA_access.hh"
60#include "RNA_define.hh"
61#include "RNA_enum_types.hh"
62
63#include "ED_gpencil_legacy.hh"
64#include "ED_object.hh"
65
66#include "DEG_depsgraph.hh"
68
69#include "gpencil_intern.hh"
70
71/* ************************************************ */
72/* Datablock Operators */
73
74/* ******************* Add New Data ************************ */
76{
77
78 /* the base line we have is that we have somewhere to add Grease Pencil data */
79 return ED_annotation_data_get_pointers(C, nullptr) != nullptr;
80}
81
82/* add new datablock - wrapper around API */
84{
85 PointerRNA gpd_owner = {nullptr};
86 bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, &gpd_owner);
87
88 if (gpd_ptr == nullptr) {
89 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
90 return OPERATOR_CANCELLED;
91 }
92
93 /* decrement user count and add new datablock */
94 /* TODO: if a datablock exists,
95 * we should make a copy of it instead of starting fresh (as in other areas) */
96 Main *bmain = CTX_data_main(C);
97
98 /* decrement user count of old GP datablock */
99 if (*gpd_ptr) {
100 bGPdata *gpd = (*gpd_ptr);
101 id_us_min(&gpd->id);
102 }
103
104 /* Add new datablock, with a single layer ready to use
105 * (so users don't have to perform an extra step). */
106 bGPdata *gpd = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
107 *gpd_ptr = gpd;
108
109 /* tag for annotations */
111
112 /* add new layer (i.e. a "note") */
113 BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true, false);
114
115 /* notifiers */
117
118 return OPERATOR_FINISHED;
119}
120
122{
123 /* identifiers */
124 ot->name = "Annotation Add New";
125 ot->idname = "GPENCIL_OT_annotation_add";
126 ot->description = "Add new Annotation data-block";
128
129 /* callbacks */
132}
133
134/* ******************* Unlink Data ************************ */
135
136/* poll callback for adding data/layers - special */
138{
139 bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, nullptr);
140
141 /* only unlink annotation datablocks */
142 if ((gpd_ptr != nullptr) && (*gpd_ptr != nullptr)) {
143 bGPdata *gpd = (*gpd_ptr);
144 if ((gpd->flag & GP_DATA_ANNOTATIONS) == 0) {
145 return false;
146 }
147 }
148 /* if we have access to some active data, make sure there's a datablock before enabling this */
149 return (gpd_ptr && *gpd_ptr);
150}
151
152/* unlink datablock - wrapper around API */
154{
155 bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, nullptr);
156
157 if (gpd_ptr == nullptr) {
158 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
159 return OPERATOR_CANCELLED;
160 }
161 /* just unlink datablock now, decreasing its user count */
162 bGPdata *gpd = (*gpd_ptr);
163
164 id_us_min(&gpd->id);
165 *gpd_ptr = nullptr;
166
167 /* notifiers */
169
170 return OPERATOR_FINISHED;
171}
172
174{
175 /* identifiers */
176 ot->name = "Annotation Unlink";
177 ot->idname = "GPENCIL_OT_data_unlink";
178 ot->description = "Unlink active Annotation data-block";
180
181 /* callbacks */
184}
185
186/* ************************************************ */
187/* Layer Operators */
188
189/* ******************* Add New Layer ************************ */
190
191/* add new layer - wrapper around API */
193{
194 const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_add");
195
196 PointerRNA gpd_owner = {nullptr};
197 Main *bmain = CTX_data_main(C);
198 Scene *scene = CTX_data_scene(C);
199 bGPdata *gpd = nullptr;
200
201 if (is_annotation) {
202 bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, &gpd_owner);
203 /* if there's no existing Grease-Pencil data there, add some */
204 if (gpd_ptr == nullptr) {
205 BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
206 return OPERATOR_CANCELLED;
207 }
208 /* Annotations */
209 if (*gpd_ptr == nullptr) {
210 *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
211 }
212
213 /* mark as annotation */
214 (*gpd_ptr)->flag |= GP_DATA_ANNOTATIONS;
215 BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true, false);
216 gpd = *gpd_ptr;
217 }
218 else {
219 /* GP Object */
221 if ((ob != nullptr) && (ob->type == OB_GPENCIL_LEGACY)) {
222 gpd = (bGPdata *)ob->data;
223 PropertyRNA *prop;
224 char name[128];
225 prop = RNA_struct_find_property(op->ptr, "new_layer_name");
226 if (RNA_property_is_set(op->ptr, prop)) {
227 RNA_property_string_get(op->ptr, prop, name);
228 }
229 else {
230 STRNCPY(name, "GP_Layer");
231 }
232 bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, name, true, false);
233
234 /* Add a new frame to make it visible in Dopesheet. */
235 if (gpl != nullptr) {
236 gpl->actframe = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW);
237 }
238 }
239 }
240
241 /* notifiers */
242 if (gpd) {
244 }
247
248 return OPERATOR_FINISHED;
249}
250
252{
253 return ED_annotation_data_get_pointers(C, nullptr) != nullptr;
254}
255
257{
258 /* identifiers */
259 ot->name = "Add New Annotation Layer";
260 ot->idname = "GPENCIL_OT_layer_annotation_add";
261 ot->description = "Add new Annotation layer or note for the active data-block";
262
264
265 /* callbacks */
268}
269/* ******************* Remove Active Layer ************************* */
270
272{
273 const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_remove");
274
275 bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) :
278
279 /* sanity checks */
280 if (ELEM(nullptr, gpd, gpl)) {
281 return OPERATOR_CANCELLED;
282 }
283
284 if (gpl->flag & GP_LAYER_LOCKED) {
285 BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
286 return OPERATOR_CANCELLED;
287 }
288
289 /* make the layer before this the new active layer
290 * - use the one after if this is the first
291 * - if this is the only layer, this naturally becomes nullptr
292 */
293 if (gpl->prev) {
295 }
296 else {
298 }
299
300 /* delete the layer now... */
301 BKE_gpencil_layer_delete(gpd, gpl);
302
303 /* Reorder masking. */
305
306 /* notifiers */
310
311 /* Free Grease Pencil data block when last annotation layer is removed, see: #112683. */
312 if (is_annotation && gpd->layers.first == nullptr) {
313 BKE_gpencil_free_data(gpd, true);
314
315 bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, nullptr);
316 *gpd_ptr = nullptr;
317
318 Main *bmain = CTX_data_main(C);
319 BKE_id_free_us(bmain, gpd);
320 }
321
322 return OPERATOR_FINISHED;
323}
324
326{
329
330 return (gpl != nullptr);
331}
332
334{
335 /* identifiers */
336 ot->name = "Remove Annotation Layer";
337 ot->idname = "GPENCIL_OT_layer_annotation_remove";
338 ot->description = "Remove active Annotation layer";
339
341
342 /* callbacks */
345}
346/* ******************* Move Layer Up/Down ************************** */
347
348enum {
351};
352
354{
355 const bool is_annotation = STREQ(op->idname, "GPENCIL_OT_layer_annotation_move");
356
357 bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) :
360
361 const int direction = RNA_enum_get(op->ptr, "type") * -1;
362
363 /* sanity checks */
364 if (ELEM(nullptr, gpd, gpl)) {
365 return OPERATOR_CANCELLED;
366 }
367
368 BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
369 if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) {
370 /* Reorder masking. */
372
375 }
376
377 return OPERATOR_FINISHED;
378}
379
381{
382 static const EnumPropertyItem slot_move[] = {
383 {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
384 {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
385 {0, nullptr, 0, nullptr, nullptr},
386 };
387
388 /* identifiers */
389 ot->name = "Move Annotation Layer";
390 ot->idname = "GPENCIL_OT_layer_annotation_move";
391 ot->description = "Move the active Annotation layer up/down in the list";
392
393 /* api callbacks */
396
397 /* flags */
399
400 ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
401}
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
support for deformation groups and hooks.
void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active)
void BKE_gpencil_free_data(struct bGPdata *gpd, bool free_all)
struct bGPDlayer * BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive, bool add_to_header)
void BKE_gpencil_layer_mask_sort_all(struct bGPdata *gpd)
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
struct bGPDlayer * BKE_gpencil_layer_active_get(struct bGPdata *gpd)
struct bGPdata * BKE_gpencil_data_addnew(struct Main *bmain, const char name[])
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl)
@ GP_GETFRAME_ADD_NEW
void BKE_id_free_us(Main *bmain, void *idv) ATTR_NONNULL()
void id_us_min(ID *id)
Definition lib_id.cc:359
General operations, lookup, etc. for materials.
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define BLI_assert(a)
Definition BLI_assert.h:50
void void void bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL()
Definition listbase.cc:435
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define ELEM(...)
#define STREQ(a, b)
#define DATA_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
Object is a sort of wrapper for general info.
@ OB_GPENCIL_LEGACY
Read Guarded memory(de)allocation.
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_DATA
Definition WM_types.hh:475
#define NA_EDITED
Definition WM_types.hh:550
#define NC_GPENCIL
Definition WM_types.hh:366
#define NA_SELECTED
Definition WM_types.hh:555
static int gpencil_layer_add_exec(bContext *C, wmOperator *op)
static bool gpencil_active_layer_annotation_poll(bContext *C)
void GPENCIL_OT_layer_annotation_move(wmOperatorType *ot)
void GPENCIL_OT_layer_annotation_remove(wmOperatorType *ot)
static bool gpencil_data_unlink_poll(bContext *C)
static bool gpencil_data_add_poll(bContext *C)
@ GP_LAYER_MOVE_DOWN
@ GP_LAYER_MOVE_UP
static bool gpencil_add_annotation_poll(bContext *C)
void GPENCIL_OT_annotation_add(wmOperatorType *ot)
static int gpencil_layer_move_exec(bContext *C, wmOperator *op)
static int gpencil_data_unlink_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_data_unlink(wmOperatorType *ot)
static int gpencil_layer_remove_exec(bContext *C, wmOperator *op)
static int gpencil_data_add_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_layer_annotation_add(wmOperatorType *ot)
bGPdata * ED_annotation_data_get_active(const bContext *C)
bGPdata * ED_gpencil_data_get_active(const bContext *C)
bGPdata ** ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
std::string RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void * first
struct bGPDlayer * next
struct bGPDlayer * prev
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4125