Blender V5.0
eyedropper_grease_pencil_color.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_listbase.h"
18
19#include "BLT_translation.hh"
20
21#include "DNA_brush_types.h"
22#include "DNA_material_types.h"
23
24#include "BKE_brush.hh"
25#include "BKE_context.hh"
26#include "BKE_grease_pencil.hh"
27#include "BKE_lib_id.hh"
28#include "BKE_material.hh"
29#include "BKE_paint.hh"
30
32
33#include "WM_api.hh"
34#include "WM_types.hh"
35
36#include "RNA_access.hh"
37#include "RNA_define.hh"
38
39#include "ED_screen.hh"
40#include "ED_undo.hh"
41
43
44#include "eyedropper_intern.hh"
45#include "interface_intern.hh"
46
48
49enum class EyeMode : int8_t {
52 Brush = 2,
53};
54
55enum class MaterialMode : int8_t {
56 Stroke = 0,
57 Fill = 1,
58 Both = 2,
59};
60
74
75/* Helper: Draw status message while the user is running the operator */
77 wmOperator *op,
78 const wmEvent *event)
79{
80 std::string header;
81 header += IFACE_("Current: ");
82
83 const bool is_ctrl = (event->modifier & KM_CTRL) != 0;
84 const bool is_shift = (event->modifier & KM_SHIFT) != 0;
85
87
88 MaterialMode mat_mode = eye->mat_mode;
89 if (is_ctrl && !is_shift) {
90 mat_mode = MaterialMode::Stroke;
91 }
92 if (is_shift && !is_ctrl) {
93 mat_mode = MaterialMode::Fill;
94 }
95 if (is_ctrl && is_shift) {
96 mat_mode = MaterialMode::Both;
97 }
98
99 switch (mat_mode) {
101 header += IFACE_("Stroke");
102 break;
103 }
104 case MaterialMode::Fill: {
105 header += IFACE_("Fill");
106 break;
107 }
108 case MaterialMode::Both: {
109 header += IFACE_("Both");
110 break;
111 }
112 }
113
114 header += IFACE_(", Ctrl: Stroke, Shift: Fill, Shift+Ctrl: Both");
115
116 ED_workspace_status_text(C, header.c_str());
117}
118
120{
121 EyedropperGreasePencil *eye = MEM_new<EyedropperGreasePencil>(__func__);
122
123 op->customdata = eye;
124 Scene *scene = CTX_data_scene(C);
125
126 const char *display_device;
127 display_device = scene->display_settings.display_device;
128 eye->display = IMB_colormanagement_display_get_named(display_device);
129
130 eye->accum_start = true;
131 eye->mode = EyeMode(RNA_enum_get(op->ptr, "mode"));
132 eye->mat_mode = MaterialMode(RNA_enum_get(op->ptr, "material_mode"));
133 return true;
134}
135
137{
138 /* Clear status message area. */
139 ED_workspace_status_text(C, nullptr);
140
142
143 MEM_delete<EyedropperGreasePencil>(eye);
144 /* Clear pointer. */
145 op->customdata = nullptr;
146}
147
148static void eyedropper_add_material(bContext *C, const float3 color, const MaterialMode mat_mode)
149{
150 Main *bmain = CTX_data_main(C);
152 Material *ma = nullptr;
153
154 bool found = false;
155
156 /* Look for a similar material in grease pencil slots. */
157 short *totcol = BKE_object_material_len_p(ob);
158 for (short i = 0; i < *totcol; i++) {
159 ma = BKE_object_material_get(ob, i + 1);
160 if (ma == nullptr) {
161 continue;
162 }
163
164 MaterialGPencilStyle *gp_style = ma->gp_style;
165 if (gp_style != nullptr) {
166 /* Check stroke color. */
167 bool found_stroke = compare_v3v3(gp_style->stroke_rgba, color, 0.01f) &&
168 (gp_style->flag & GP_MATERIAL_STROKE_SHOW);
169 /* Check fill color. */
170 bool found_fill = compare_v3v3(gp_style->fill_rgba, color, 0.01f) &&
171 (gp_style->flag & GP_MATERIAL_FILL_SHOW);
172
173 if ((mat_mode == MaterialMode::Stroke) && (found_stroke) &&
174 ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0))
175 {
176 found = true;
177 }
178 else if ((mat_mode == MaterialMode::Fill) && found_fill &&
179 ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0))
180 {
181 found = true;
182 }
183 else if ((mat_mode == MaterialMode::Both) && found_stroke && found_fill) {
184 found = true;
185 }
186
187 /* Found existing material. */
188 if (found) {
189 ob->actcol = i + 1;
192 return;
193 }
194 }
195 }
196
197 /* If material was not found add a new material with stroke and/or fill color
198 * depending of the secondary key (LMB: Stroke, Shift: Fill, Shift+Ctrl: Stroke/Fill)
199 */
200 int idx;
201 Material *ma_new = BKE_grease_pencil_object_material_new(bmain, ob, "Material", &idx);
205
206 BLI_assert(ma_new != nullptr);
207
208 MaterialGPencilStyle *gp_style_new = ma_new->gp_style;
209 BLI_assert(gp_style_new != nullptr);
210
211 /* Only create Stroke (default option). */
212 if (mat_mode == MaterialMode::Stroke) {
213 /* Stroke color. */
214 gp_style_new->flag |= GP_MATERIAL_STROKE_SHOW;
215 gp_style_new->flag &= ~GP_MATERIAL_FILL_SHOW;
216 copy_v3_v3(gp_style_new->stroke_rgba, color);
217 zero_v4(gp_style_new->fill_rgba);
218 }
219 /* Fill Only. */
220 else if (mat_mode == MaterialMode::Fill) {
221 /* Fill color. */
222 gp_style_new->flag &= ~GP_MATERIAL_STROKE_SHOW;
223 gp_style_new->flag |= GP_MATERIAL_FILL_SHOW;
224 zero_v4(gp_style_new->stroke_rgba);
225 copy_v3_v3(gp_style_new->fill_rgba, color);
226 }
227 /* Stroke and Fill. */
228 else if (mat_mode == MaterialMode::Both) {
230 copy_v3_v3(gp_style_new->stroke_rgba, color);
231 copy_v3_v3(gp_style_new->fill_rgba, color);
232 }
233 /* Push undo for new created material. */
234 ED_undo_push(C, "Add Grease Pencil Material");
235}
236
237/* Create a new palette color and palette if needed. */
239{
240 Main *bmain = CTX_data_main(C);
241 Scene *scene = CTX_data_scene(C);
242 ToolSettings *ts = scene->toolsettings;
243 GpPaint *gp_paint = ts->gp_paint;
244 GpVertexPaint *gp_vertexpaint = ts->gp_vertexpaint;
245 Paint *paint = &gp_paint->paint;
246 Paint *vertexpaint = &gp_vertexpaint->paint;
247
248 /* Check for Palette in Draw and Vertex Paint Mode. */
249 if (paint->palette == nullptr) {
250 Palette *palette = BKE_palette_add(bmain, "Grease Pencil");
251 id_us_min(&palette->id);
252
253 BKE_paint_palette_set(paint, palette);
254
255 if (vertexpaint->palette == nullptr) {
256 BKE_paint_palette_set(vertexpaint, palette);
257 }
258 }
259
260 /* Check if the color exist already. */
261 Palette *palette = paint->palette;
262 int i;
263 LISTBASE_FOREACH_INDEX (PaletteColor *, palcolor, &palette->colors, i) {
264 if (compare_v3v3(palcolor->color, color, 0.01f)) {
265 palette->active_color = i;
266 return;
267 }
268 }
269
270 /* Create Colors. */
271 PaletteColor *palcol = BKE_palette_color_add(palette);
272 if (palcol) {
273 palette->active_color = BLI_listbase_count(&palette->colors) - 1;
275 }
276}
277
278/* Set the active brush's color. */
280{
281 Scene *scene = CTX_data_scene(C);
282 ToolSettings *ts = scene->toolsettings;
283 Paint *paint = &ts->gp_paint->paint;
284 Brush *brush = BKE_paint_brush(paint);
285 if (brush == nullptr) {
286 return;
287 }
288
289 copy_v3_v3(brush->color, color);
292}
293
294/* Set the material or the palette color. */
296 const wmEvent *event,
298{
299 const bool is_ctrl = (event->modifier & KM_CTRL) != 0;
300 const bool is_shift = (event->modifier & KM_SHIFT) != 0;
301
302 MaterialMode mat_mode = eye->mat_mode;
303 if (is_ctrl && !is_shift) {
304 mat_mode = MaterialMode::Stroke;
305 }
306 if (is_shift && !is_ctrl) {
307 mat_mode = MaterialMode::Fill;
308 }
309 if (is_ctrl && is_shift) {
310 mat_mode = MaterialMode::Both;
311 }
312
313 switch (eye->mode) {
315 eyedropper_add_material(C, eye->color, mat_mode);
316 break;
317 case EyeMode::Palette:
319 break;
320 case EyeMode::Brush:
322 break;
323 }
324}
325
326/* Sample the color below cursor. */
329 const int m_xy[2])
330{
331 /* Accumulate color. */
332 float3 col;
333 eyedropper_color_sample_fl(C, nullptr, m_xy, col);
334
335 eye->accum_col += col;
336 eye->accum_tot++;
337
338 eye->color = eye->accum_col;
339 if (eye->accum_tot > 1) {
340 eye->color = eye->accum_col / float(eye->accum_tot);
341 }
342}
343
348
349/* Main modal status check. */
351 wmOperator *op,
352 const wmEvent *event)
353{
356
357 /* Handle modal keymap */
358 switch (event->type) {
359 case EVT_MODAL_MAP: {
360 switch (event->val) {
362 /* enable accum and make first sample */
363 eye->accum_start = true;
365 break;
367 eye->accum_tot = 0;
368 eye->accum_col = float3(0.0f, 0.0f, 0.0f);
370 break;
371 case EYE_MODAL_CANCEL: {
373 return OPERATOR_CANCELLED;
374 }
377
378 /* Create material. */
381
383 return OPERATOR_FINISHED;
384 }
385 default: {
386 break;
387 }
388 }
389 break;
390 }
391 case MOUSEMOVE:
392 case INBETWEEN_MOUSEMOVE: {
393 if (eye->accum_start) {
394 /* button is pressed so keep sampling */
396 }
397 break;
398 }
399 default: {
400 break;
401 }
402 }
403
405}
406
408 wmOperator *op,
409 const wmEvent *event)
410{
412 /* Add modal temp handler. */
414 /* Status message. */
416
418 }
420}
421
422/* Repeat operator */
424{
426
427 /* cleanup */
429
430 return OPERATOR_FINISHED;
431 }
433}
434
436{
437 /* Only valid if the current active object is grease pencil. */
439 if ((obact == nullptr) || (obact->type != OB_GREASE_PENCIL)) {
440 return false;
441 }
442
443 /* Test we have a window below. */
444 return (CTX_wm_window(C) != nullptr);
445}
446
447} // namespace blender::ui::greasepencil
448
450{
451 using namespace blender::ui::greasepencil;
452 static const EnumPropertyItem items_mode[] = {
453 {int(EyeMode::Material), "MATERIAL", 0, "Material", ""},
454 {int(EyeMode::Palette), "PALETTE", 0, "Palette", ""},
455 {int(EyeMode::Brush), "BRUSH", 0, "Brush", ""},
456 {0, nullptr, 0, nullptr, nullptr},
457 };
458
459 static const EnumPropertyItem items_material_mode[] = {
460 {int(MaterialMode::Stroke), "STROKE", 0, "Stroke", ""},
461 {int(MaterialMode::Fill), "FILL", 0, "Fill", ""},
462 {int(MaterialMode::Both), "BOTH", 0, "Both", ""},
463 {0, nullptr, 0, nullptr, nullptr},
464 };
465
466 /* Identifiers. */
467 ot->name = "Grease Pencil Eyedropper";
468 ot->idname = "UI_OT_eyedropper_grease_pencil_color";
469 ot->description = "Sample a color from the Blender Window and create Grease Pencil material";
470
471 /* API callbacks. */
477
478 /* Flags. */
480
481 /* Properties. */
482 ot->prop = RNA_def_enum(ot->srna, "mode", items_mode, int(EyeMode::Material), "Mode", "");
483 ot->prop = RNA_def_enum(ot->srna,
484 "material_mode",
485 items_material_mode,
487 "Material Mode",
488 "");
489}
void BKE_brush_color_sync_legacy(Brush *brush)
Definition brush.cc:1227
void BKE_brush_tag_unsaved_changes(Brush *brush)
Definition brush.cc:764
wmWindow * CTX_wm_window(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
Low-level operations for grease pencil.
Material * BKE_grease_pencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
void id_us_min(ID *id)
Definition lib_id.cc:366
General operations, lookup, etc. for materials.
short * BKE_object_material_len_p(Object *ob)
Material * BKE_object_material_get(Object *ob, short act)
PaletteColor * BKE_palette_color_add(Palette *palette)
Definition paint.cc:1433
Palette * BKE_palette_add(Main *bmain, const char *name)
Definition paint.cc:1427
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:645
void BKE_palette_color_set(PaletteColor *color, const float rgb[3])
Definition paint.cc:1416
void BKE_paint_palette_set(Paint *paint, Palette *palette)
Definition paint.cc:1380
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v4(float r[4])
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
#define IFACE_(msgid)
void DEG_relations_tag_update(Main *bmain)
@ GP_MATERIAL_STROKE_SHOW
@ GP_MATERIAL_FILL_SHOW
@ OB_GREASE_PENCIL
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:1024
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:98
const ColorManagedDisplay * IMB_colormanagement_display_get_named(const char *name)
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
blender::ocio::Display ColorManagedDisplay
@ KM_CTRL
Definition WM_types.hh:279
@ KM_SHIFT
Definition WM_types.hh:278
#define ND_DATA
Definition WM_types.hh:509
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_UNDO
Definition WM_types.hh:182
#define NA_EDITED
Definition WM_types.hh:584
#define NC_MATERIAL
Definition WM_types.hh:380
#define NC_GPENCIL
Definition WM_types.hh:399
#define ND_OB_SHADING
Definition WM_types.hh:457
#define ND_SPACE_VIEW3D
Definition WM_types.hh:528
#define NC_OBJECT
Definition WM_types.hh:379
#define ND_SHADING_LINKS
Definition WM_types.hh:479
#define NC_SPACE
Definition WM_types.hh:392
nullptr float
bool eyedropper_color_sample_fl(bContext *C, Eyedropper *eye, const int event_xy[2], float r_col[3])
void UI_OT_eyedropper_grease_pencil_color(wmOperatorType *ot)
@ EYE_MODAL_SAMPLE_BEGIN
@ EYE_MODAL_SAMPLE_RESET
@ EYE_MODAL_CANCEL
@ EYE_MODAL_SAMPLE_CONFIRM
uint col
static void eyedropper_add_palette_color(bContext *C, const float3 color)
static bool eyedropper_grease_pencil_poll(bContext *C)
static wmOperatorStatus eyedropper_grease_pencil_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void eyedropper_grease_pencil_color_sample(bContext *C, EyedropperGreasePencil *eye, const int m_xy[2])
static void eyedropper_grease_pencil_exit(bContext *C, wmOperator *op)
static bool eyedropper_grease_pencil_init(bContext *C, wmOperator *op)
static void eyedropper_grease_pencil_status_indicators(bContext *C, wmOperator *op, const wmEvent *event)
static void eyedropper_grease_pencil_cancel(bContext *C, wmOperator *op)
static void eyedropper_set_brush_color(bContext *C, const float3 &color)
static wmOperatorStatus eyedropper_grease_pencil_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void eyedropper_add_material(bContext *C, const float3 color, const MaterialMode mat_mode)
static wmOperatorStatus eyedropper_grease_pencil_exec(bContext *C, wmOperator *op)
static void eyedropper_grease_pencil_color_set(bContext *C, const wmEvent *event, EyedropperGreasePencil *eye)
VecBase< float, 3 > float3
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)
float color[3]
struct MaterialGPencilStyle * gp_style
struct Palette * palette
ListBase colors
struct ToolSettings * toolsettings
ColorManagedDisplaySettings display_settings
GpVertexPaint * gp_vertexpaint
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int xy[2]
Definition WM_types.hh:761
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ EVT_MODAL_MAP
@ MOUSEMOVE
@ INBETWEEN_MOUSEMOVE
wmOperatorType * ot
Definition wm_files.cc:4237