Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/gpencil/gpencil_data.c
| Context not available. | |||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "DNA_object_types.h" | |||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "DNA_space_types.h" | #include "DNA_space_types.h" | ||||
| #include "DNA_view3d_types.h" | #include "DNA_view3d_types.h" | ||||
| #include "DNA_gpencil_types.h" | #include "DNA_gpencil_types.h" | ||||
| #include "DNA_brush_types.h" | |||||
| #include "BKE_main.h" | |||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_gpencil.h" | #include "BKE_gpencil.h" | ||||
| #include "BKE_paint.h" | |||||
| #include "BKE_library.h" | #include "BKE_library.h" | ||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| Context not available. | |||||
| static int gp_data_add_exec(bContext *C, wmOperator *op) | static int gp_data_add_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); | bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); | ||||
| ToolSettings *ts = CTX_data_tool_settings(C); | |||||
| if (gpd_ptr == NULL) { | if (gpd_ptr == NULL) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); | BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); | ||||
| Context not available. | |||||
| id_us_min(&gpd->id); | id_us_min(&gpd->id); | ||||
| *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); | *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); | ||||
| /* if not exist brushes, create a new set */ | /* add default sets of colors and brushes */ | ||||
| if (ts) { | ED_gpencil_add_defaults(C); | ||||
| if (BLI_listbase_is_empty(&ts->gp_brushes)) { | |||||
| /* create new brushes */ | |||||
| BKE_gpencil_brush_init_presets(ts); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| /* notifiers */ | /* notifiers */ | ||||
| Context not available. | |||||
| static int gp_layer_add_exec(bContext *C, wmOperator *op) | static int gp_layer_add_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); | bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); | ||||
| ToolSettings *ts = CTX_data_tool_settings(C); | |||||
| /* if there's no existing Grease-Pencil data there, add some */ | /* if there's no existing Grease-Pencil data there, add some */ | ||||
| if (gpd_ptr == NULL) { | if (gpd_ptr == NULL) { | ||||
| Context not available. | |||||
| if (*gpd_ptr == NULL) | if (*gpd_ptr == NULL) | ||||
| *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); | *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); | ||||
| /* if not exist brushes, create a new set */ | /* add default sets of colors and brushes */ | ||||
| if (ts) { | ED_gpencil_add_defaults(C); | ||||
| if (BLI_listbase_is_empty(&ts->gp_brushes)) { | |||||
| /* create new brushes */ | |||||
| BKE_gpencil_brush_init_presets(ts); | |||||
| } | |||||
| } | |||||
| /* add new layer now */ | /* add new layer now */ | ||||
| BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true); | BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true); | ||||
| Context not available. | |||||
| BKE_gpencil_layer_delete(gpd, gpl); | BKE_gpencil_layer_delete(gpd, gpl); | ||||
| /* notifiers */ | /* notifiers */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */ | BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */ | ||||
| if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) { | if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) { | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| } | } | ||||
| Context not available. | |||||
| BKE_gpencil_layer_setactive(gpd, new_layer); | BKE_gpencil_layer_setactive(gpd, new_layer); | ||||
| /* notifiers */ | /* notifiers */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| } | } | ||||
| /* notifiers */ | /* notifiers */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| } | } | ||||
| /* notifiers */ | /* notifiers */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| } | } | ||||
| /* notifiers */ | /* notifiers */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| } | } | ||||
| /* notifiers */ | /* notifiers */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| } | } | ||||
| /* notifiers */ | /* notifiers */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| BLI_ghash_free(gh_frames_cur, NULL, NULL); | BLI_ghash_free(gh_frames_cur, NULL, NULL); | ||||
| /* notifiers */ | /* notifiers */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| BKE_gpencil_layer_setactive(gpd, gpl); | BKE_gpencil_layer_setactive(gpd, gpl); | ||||
| /* updates */ | /* updates */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| bGPDframe *gpf = gpl->actframe; | |||||
| /* temp listbase to store selected strokes */ | |||||
| ListBase selected = {NULL}; | |||||
| const int direction = RNA_enum_get(op->ptr, "direction"); | const int direction = RNA_enum_get(op->ptr, "direction"); | ||||
| /* verify if any selected stroke is in the extreme of the stack and select to move */ | for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { | ||||
| for (gps = gpf->strokes.first; gps; gps = gps->next) { | /* temp listbase to store selected strokes by layer */ | ||||
| /* only if selected */ | ListBase selected = { NULL }; | ||||
| if (gps->flag & GP_STROKE_SELECT) { | bGPDframe *gpf = gpl->actframe; | ||||
| /* skip strokes that are invalid for current view */ | if (gpl->flag & GP_LAYER_LOCKED) { | ||||
| if (ED_gpencil_stroke_can_use(C, gps) == false) { | continue; | ||||
| continue; | } | ||||
| } | |||||
| /* check if the color is editable */ | if (gpf == NULL) { | ||||
| if (ED_gpencil_stroke_color_use(gpl, gps) == false) { | continue; | ||||
| continue; | } | ||||
| } | bool gpf_lock = false; | ||||
| /* some stroke is already at front*/ | /* verify if any selected stroke is in the extreme of the stack and select to move */ | ||||
| if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) { | for (gps = gpf->strokes.first; gps; gps = gps->next) { | ||||
| if (gps == gpf->strokes.last) { | /* only if selected */ | ||||
| return OPERATOR_CANCELLED; | if (gps->flag & GP_STROKE_SELECT) { | ||||
| /* skip strokes that are invalid for current view */ | |||||
| if (ED_gpencil_stroke_can_use(C, gps) == false) { | |||||
| continue; | |||||
| } | } | ||||
| } | /* check if the color is editable */ | ||||
| /* some stroke is already at botom */ | if (ED_gpencil_stroke_color_use(gpl, gps) == false) { | ||||
| if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) { | continue; | ||||
| if (gps == gpf->strokes.first) { | } | ||||
| return OPERATOR_CANCELLED; | /* some stroke is already at front*/ | ||||
| if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) { | |||||
| if (gps == gpf->strokes.last) { | |||||
| gpf_lock = true; | |||||
| continue; | |||||
| } | |||||
| } | |||||
| /* some stroke is already at botom */ | |||||
| if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) { | |||||
| if (gps == gpf->strokes.first) { | |||||
| gpf_lock = true; | |||||
| continue; | |||||
| } | |||||
| } | |||||
| /* add to list (if not locked) */ | |||||
| if (!gpf_lock) { | |||||
| BLI_addtail(&selected, BLI_genericNodeN(gps)); | |||||
| } | } | ||||
| } | } | ||||
| /* add to list */ | |||||
| BLI_addtail(&selected, BLI_genericNodeN(gps)); | |||||
| } | } | ||||
| } | /* Now do the movement of the stroke */ | ||||
| if (!gpf_lock) { | |||||
| /* Now do the movement of the stroke */ | switch (direction) { | ||||
| switch (direction) { | /* Bring to Front */ | ||||
| /* Bring to Front */ | case GP_STROKE_MOVE_TOP: | ||||
| case GP_STROKE_MOVE_TOP: | for (LinkData *link = selected.first; link; link = link->next) { | ||||
| for (LinkData *link = selected.first; link; link = link->next) { | gps = link->data; | ||||
| gps = link->data; | BLI_remlink(&gpf->strokes, gps); | ||||
| BLI_remlink(&gpf->strokes, gps); | BLI_addtail(&gpf->strokes, gps); | ||||
| BLI_addtail(&gpf->strokes, gps); | } | ||||
| } | break; | ||||
| break; | /* Bring Forward */ | ||||
| /* Bring Forward */ | case GP_STROKE_MOVE_UP: | ||||
| case GP_STROKE_MOVE_UP: | for (LinkData *link = selected.last; link; link = link->prev) { | ||||
| for (LinkData *link = selected.last; link; link = link->prev) { | gps = link->data; | ||||
| gps = link->data; | BLI_listbase_link_move(&gpf->strokes, gps, 1); | ||||
| BLI_listbase_link_move(&gpf->strokes, gps, 1); | } | ||||
| } | break; | ||||
| break; | /* Send Backward */ | ||||
| /* Send Backward */ | case GP_STROKE_MOVE_DOWN: | ||||
| case GP_STROKE_MOVE_DOWN: | for (LinkData *link = selected.first; link; link = link->next) { | ||||
| for (LinkData *link = selected.first; link; link = link->next) { | gps = link->data; | ||||
| gps = link->data; | BLI_listbase_link_move(&gpf->strokes, gps, -1); | ||||
| BLI_listbase_link_move(&gpf->strokes, gps, -1); | } | ||||
| } | break; | ||||
| break; | /* Send to Back */ | ||||
| /* Send to Back */ | case GP_STROKE_MOVE_BOTTOM: | ||||
| case GP_STROKE_MOVE_BOTTOM: | for (LinkData *link = selected.last; link; link = link->prev) { | ||||
| for (LinkData *link = selected.last; link; link = link->prev) { | gps = link->data; | ||||
| gps = link->data; | BLI_remlink(&gpf->strokes, gps); | ||||
| BLI_remlink(&gpf->strokes, gps); | BLI_addhead(&gpf->strokes, gps); | ||||
| BLI_addhead(&gpf->strokes, gps); | } | ||||
| break; | |||||
| default: | |||||
| BLI_assert(0); | |||||
| break; | |||||
| } | } | ||||
| break; | } | ||||
| default: | BLI_freelistN(&selected); | ||||
| BLI_assert(0); | |||||
| break; | |||||
| } | } | ||||
| BLI_freelistN(&selected); | |||||
| /* notifiers */ | /* notifiers */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| ot->idname = "GPENCIL_OT_stroke_arrange"; | ot->idname = "GPENCIL_OT_stroke_arrange"; | ||||
| ot->description = "Arrange selected strokes up/down in the drawing order of the active layer"; | ot->description = "Arrange selected strokes up/down in the drawing order of the active layer"; | ||||
| /* api callbacks */ | /* callbacks */ | ||||
| ot->exec = gp_stroke_arrange_exec; | ot->exec = gp_stroke_arrange_exec; | ||||
| ot->poll = gp_active_layer_poll; | ot->poll = gp_active_layer_poll; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* properties */ | |||||
| ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_STROKE_MOVE_UP, "Direction", ""); | ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_STROKE_MOVE_UP, "Direction", ""); | ||||
| } | } | ||||
| /* ******************* Move Stroke to new palette ************************** */ | |||||
| static int gp_stroke_change_palette_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| const int type = RNA_enum_get(op->ptr, "type"); | |||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| bGPDpaletteref *palslot = BKE_gpencil_paletteslot_get_active(gpd); | |||||
| Palette *palette; | |||||
| PaletteColor *palcolor; | |||||
| /* sanity checks */ | |||||
| if (ELEM(NULL, gpd, palslot)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| palette = palslot->palette; | |||||
| if (ELEM(NULL, palette)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| /* loop all strokes */ | |||||
| for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { | |||||
| /* only editable and visible layers are considered */ | |||||
| if (!gpencil_layer_is_editable(gpl)) | |||||
| continue; | |||||
| for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { | |||||
| /* check frame if frame range */ | |||||
| if ((type == GP_MOVE_PALETTE_BEFORE) && (gpf->framenum >= scene->r.cfra)) | |||||
| continue; | |||||
| if ((type == GP_MOVE_PALETTE_AFTER) && (gpf->framenum < scene->r.cfra)) | |||||
| continue; | |||||
| if ((type == GP_MOVE_PALETTE_CURRENT) && (gpf->framenum != scene->r.cfra)) | |||||
| continue; | |||||
| for (bGPDstroke *gps = gpf->strokes.last; gps; gps = gps->prev) { | |||||
| /* only if selected */ | |||||
| if (((gps->flag & GP_STROKE_SELECT) == 0) && (type == GP_MOVE_PALETTE_SELECT)) | |||||
| continue; | |||||
| /* skip strokes that are invalid for current view */ | |||||
| if (ED_gpencil_stroke_can_use(C, gps) == false) | |||||
| continue; | |||||
| /* check if the color is editable */ | |||||
| if (ED_gpencil_stroke_color_use(gpl, gps) == false) | |||||
| continue; | |||||
| /* look for new color */ | |||||
| palcolor = BKE_palette_color_getbyname(palette, gps->colorname); | |||||
| /* if the color does not exist, create a new one to keep stroke */ | |||||
| if (palcolor == NULL) { | |||||
| palcolor = BKE_palette_color_add_name(palette, gps->colorname); | |||||
| copy_v4_v4(palcolor->rgb, gps->palcolor->rgb); | |||||
| copy_v4_v4(palcolor->fill, gps->palcolor->fill); | |||||
| /* duplicate flags */ | |||||
| palcolor->flag = gps->palcolor->flag; | |||||
| palcolor->stroke_style = gps->palcolor->stroke_style; | |||||
| palcolor->fill_style = gps->palcolor->fill_style; | |||||
| } | |||||
| /* asign new color */ | |||||
| BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname)); | |||||
| gps->palette = palette; | |||||
| gps->palcolor = palcolor; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* notifiers */ | |||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void GPENCIL_OT_stroke_change_palette(wmOperatorType *ot) | |||||
| { | |||||
| static EnumPropertyItem palette_move_type[] = { | |||||
| { GP_MOVE_PALETTE_SELECT, "SELECTED", 0, "Change Strokes Selected", "Move to new palette any stroke selected in any frame" }, | |||||
| { GP_MOVE_PALETTE_ALL, "ALL", 0, "Change All Frames", "Move all strokes in all frames to new palette" }, | |||||
| { GP_MOVE_PALETTE_BEFORE, "BEFORE", 0, "Change Frames Before", "Move all strokes in frames before current frame to new palette" }, | |||||
| { GP_MOVE_PALETTE_AFTER, "AFTER", 0, "Change Frames After", "Move all strokes in frames greater or equal current frame to new palette" }, | |||||
| { GP_MOVE_PALETTE_CURRENT, "CURRENT", 0, "Change Current Frame", "Move all strokes in current frame to new palette" }, | |||||
| { 0, NULL, 0, NULL, NULL } | |||||
| }; | |||||
| /* identifiers */ | |||||
| ot->name = "Change Stroke Palette"; | |||||
| ot->idname = "GPENCIL_OT_stroke_change_palette"; | |||||
| ot->description = "Move strokes to active palette"; | |||||
| /* callbacks */ | |||||
| ot->exec = gp_stroke_change_palette_exec; | |||||
| ot->poll = gp_active_layer_poll; | |||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| /* properties */ | |||||
| ot->prop = RNA_def_enum(ot->srna, "type", palette_move_type, GP_MOVE_PALETTE_SELECT, "Type", ""); | |||||
| } | |||||
| /* ******************* Move Stroke to new color ************************** */ | /* ******************* Move Stroke to new color ************************** */ | ||||
| static int gp_stroke_change_color_exec(bContext *C, wmOperator *UNUSED(op)) | static int gp_stroke_change_color_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | bGPdata *gpd = ED_gpencil_data_get_active(C); | ||||
| bGPDpalette *palette; | bGPDpaletteref *palslot = BKE_gpencil_paletteslot_get_active(gpd); | ||||
| bGPDpalettecolor *color; | Palette *palette; | ||||
| PaletteColor *color; | |||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, gpd)) { | if (ELEM(NULL, gpd, palslot)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| palette = BKE_gpencil_palette_getactive(gpd); | palette = palslot->palette; | ||||
| color = BKE_gpencil_palettecolor_getactive(palette); | color = BKE_palette_color_get_active(palette); | ||||
| if (ELEM(NULL, palette, color)) { | if (ELEM(NULL, color)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| Context not available. | |||||
| /* asign new color (only if different) */ | /* asign new color (only if different) */ | ||||
| if ((STREQ(gps->colorname, color->info) == false) || (gps->palcolor != color)) { | if ((STREQ(gps->colorname, color->info) == false) || (gps->palcolor != color)) { | ||||
| BLI_strncpy(gps->colorname, color->info, sizeof(gps->colorname)); | BLI_strncpy(gps->colorname, color->info, sizeof(gps->colorname)); | ||||
| gps->palette = palette; | |||||
| gps->palcolor = color; | gps->palcolor = color; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| /* notifiers */ | /* notifiers */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| ot->idname = "GPENCIL_OT_stroke_change_color"; | ot->idname = "GPENCIL_OT_stroke_change_color"; | ||||
| ot->description = "Move selected strokes to active color"; | ot->description = "Move selected strokes to active color"; | ||||
| /* api callbacks */ | /* callbacks */ | ||||
| ot->exec = gp_stroke_change_color_exec; | ot->exec = gp_stroke_change_color_exec; | ||||
| ot->poll = gp_active_layer_poll; | ot->poll = gp_active_layer_poll; | ||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| } | } | ||||
| /* ******************* Lock color of non selected Strokes colors ************************** */ | /* ******************* Lock color of non selected Strokes colors ************************** */ | ||||
| Context not available. | |||||
| static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op)) | static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | bGPdata *gpd = ED_gpencil_data_get_active(C); | ||||
| bGPDpalette *palette; | bGPDpaletteref *palslot = BKE_gpencil_paletteslot_get_active(gpd); | ||||
| Palette *palette; | |||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, gpd)) | if (ELEM(NULL, gpd, palslot)) | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| palette = BKE_gpencil_palette_getactive(gpd); | palette = palslot->palette; | ||||
| if (ELEM(NULL, palette)) | if (ELEM(NULL, palette)) | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| /* first lock all colors */ | /* first lock all colors */ | ||||
| for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { | for (PaletteColor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { | ||||
| palcolor->flag |= PC_COLOR_LOCKED; | palcolor->flag |= PC_COLOR_LOCKED; | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| /* notifiers */ | /* notifiers */ | ||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| Context not available. | |||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->exec = gp_stroke_lock_color_exec; | ot->exec = gp_stroke_lock_color_exec; | ||||
| ot->poll = gp_active_layer_poll; | ot->poll = gp_active_layer_poll; | ||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| } | |||||
| /* ************************************************ */ | |||||
| /* Palette Slot Operators */ | |||||
| /* ********************* Add Palette SLot ************************* */ | |||||
| static int gp_paletteslot_add_exec(bContext *C, wmOperator *UNUSED(op)) | |||||
| { | |||||
| bGPdata *gpd = CTX_data_gpencil_data(C); | |||||
| /* just add an empty slot */ | |||||
| BKE_gpencil_paletteslot_add(gpd, NULL); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_ADDED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void GPENCIL_OT_palette_slot_add(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Add Palette Slot"; | |||||
| ot->idname = "GPENCIL_OT_palette_slot_add"; | |||||
| ot->description = "Add new Palette Slot to refer to a Palette used by this Grease Pencil object"; | |||||
| /* callbacks */ | |||||
| ot->exec = gp_paletteslot_add_exec; | |||||
| ot->poll = gp_active_layer_poll; // XXX | |||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| } | |||||
| /* ******************* Remove Palette Slot *********************** */ | |||||
| static int gp_paletteslot_active_poll(bContext *C) | |||||
| { | |||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| bGPDpaletteref *palslot = BKE_gpencil_paletteslot_get_active(gpd); | |||||
| return (palslot != NULL); | |||||
| } | |||||
| static int gp_paletteslot_remove_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| bGPDpaletteref *palslot = BKE_gpencil_paletteslot_get_active(gpd); | |||||
| /* 1) Check if palette is still used anywhere */ | |||||
| if (BKE_gpencil_paletteslot_has_users(gpd, palslot)) { | |||||
| /* XXX: Change strokes to the new active slot's palette instead? */ | |||||
| BKE_report(op->reports, RPT_ERROR, "Cannot remove, Palette still in use"); | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| /* 2) Remove the slot (will unlink user and free it) */ | |||||
| if ((palslot->next == NULL) && (gpd->active_palette_slot > 0)) { | |||||
| /* fix active slot index */ | |||||
| gpd->active_palette_slot--; | |||||
| } | |||||
| BKE_gpencil_palette_slot_free(gpd, palslot); | |||||
| /* updates */ | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_REMOVED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void GPENCIL_OT_palette_slot_remove(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Remove Palette Slot"; | |||||
| ot->idname = "GPENCIL_OT_palette_slot_remove"; | |||||
| ot->description = "Remove active Palette Slot to refer to a Palette used by this Grease Pencil object"; | |||||
| /* callbacks */ | |||||
| ot->exec = gp_paletteslot_remove_exec; | |||||
| ot->poll = gp_paletteslot_active_poll; | |||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| } | } | ||||
| /* ************************************************ */ | /* ************************************************ */ | ||||
| /* Drawing Brushes Operators */ | /* Drawing Brushes Operators */ | ||||
| Context not available. | |||||
| ot->idname = "GPENCIL_OT_brush_add"; | ot->idname = "GPENCIL_OT_brush_add"; | ||||
| ot->description = "Add new Grease Pencil drawing brush for the active Grease Pencil data-block"; | ot->description = "Add new Grease Pencil drawing brush for the active Grease Pencil data-block"; | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| /* callbacks */ | /* callbacks */ | ||||
| ot->exec = gp_brush_add_exec; | ot->exec = gp_brush_add_exec; | ||||
| ot->poll = gp_add_poll; | ot->poll = gp_add_poll; | ||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| } | } | ||||
| /* ******************* Remove Active Brush ************************* */ | /* ******************* Remove Active Brush ************************* */ | ||||
| Context not available. | |||||
| ot->idname = "GPENCIL_OT_brush_remove"; | ot->idname = "GPENCIL_OT_brush_remove"; | ||||
| ot->description = "Remove active Grease Pencil drawing brush"; | ot->description = "Remove active Grease Pencil drawing brush"; | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| /* callbacks */ | /* callbacks */ | ||||
| ot->exec = gp_brush_remove_exec; | ot->exec = gp_brush_remove_exec; | ||||
| ot->poll = gp_active_brush_poll; | ot->poll = gp_active_brush_poll; | ||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| } | } | ||||
| /* ********************** Change Brush ***************************** */ | /* ********************** Change Brush ***************************** */ | ||||
| Context not available. | |||||
| RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Drawing Brush", 0, INT_MAX); | RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Drawing Brush", 0, INT_MAX); | ||||
| } | } | ||||
| /* ************************************************ */ | /* ***************** Select Sculpt Brush ************************ */ | ||||
| /* Palette Operators */ | |||||
| /* ******************* Add New Palette ************************ */ | |||||
| /* add new palette - wrapper around API */ | static int gp_sculpt_select_exec(bContext *C, wmOperator *op) | ||||
| static int gp_palette_add_exec(bContext *C, wmOperator *op) | |||||
| { | { | ||||
| bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); | ToolSettings *ts = CTX_data_tool_settings(C); | ||||
| /* if there's no existing Grease-Pencil data there, add some */ | /* if there's no existing container */ | ||||
| if (gpd_ptr == NULL) { | if (ts == NULL) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); | BKE_report(op->reports, RPT_ERROR, "Nowhere to go"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| if (*gpd_ptr == NULL) | |||||
| *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); | |||||
| /* add new palette now */ | |||||
| BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true); | |||||
| /* notifiers */ | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void GPENCIL_OT_palette_add(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Add Palette"; | |||||
| ot->idname = "GPENCIL_OT_palette_add"; | |||||
| ot->description = "Add new Grease Pencil palette for the active Grease Pencil data-block"; | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| /* callbacks */ | |||||
| ot->exec = gp_palette_add_exec; | |||||
| ot->poll = gp_add_poll; | |||||
| } | |||||
| /* ******************* Remove Active Palette ************************* */ | |||||
| static int gp_palette_remove_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); | |||||
| const int index = RNA_int_get(op->ptr, "index"); | |||||
| GP_BrushEdit_Settings *gp_sculpt = &ts->gp_sculpt; | |||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, gpd, palette)) | if (ELEM(NULL, gp_sculpt)) { | ||||
| return OPERATOR_CANCELLED; | |||||
| if (BLI_listbase_count_ex(&gpd->palettes, 2) < 2) { | |||||
| BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette, unable to delete the last one"); | |||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| if (index < TOT_GP_EDITBRUSH_TYPES - 1) { | |||||
| /* make the palette before this the new active palette | gp_sculpt->brushtype = index; | ||||
| * - use the one after if this is the first | |||||
| * - if this is the only palette, this naturally becomes NULL | |||||
| */ | |||||
| if (palette->prev) | |||||
| BKE_gpencil_palette_setactive(gpd, palette->prev); | |||||
| else | |||||
| BKE_gpencil_palette_setactive(gpd, palette->next); | |||||
| /* delete the palette now... */ | |||||
| BKE_gpencil_palette_delete(gpd, palette); | |||||
| /* notifiers */ | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void GPENCIL_OT_palette_remove(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Remove palette"; | |||||
| ot->idname = "GPENCIL_OT_palette_remove"; | |||||
| ot->description = "Remove active Grease Pencil palette"; | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| /* callbacks */ | |||||
| ot->exec = gp_palette_remove_exec; | |||||
| ot->poll = gp_active_palette_poll; | |||||
| } | |||||
| /* ********************** Change Palette ***************************** */ | |||||
| static int gp_palette_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt)) | |||||
| { | |||||
| uiPopupMenu *pup; | |||||
| uiLayout *layout; | |||||
| /* call the menu, which will call this operator again, hence the canceled */ | |||||
| pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE); | |||||
| layout = UI_popup_menu_layout(pup); | |||||
| uiItemsEnumO(layout, "GPENCIL_OT_palette_change", "palette"); | |||||
| UI_popup_menu_end(C, pup); | |||||
| return OPERATOR_INTERFACE; | |||||
| } | |||||
| static int gp_palette_change_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| bGPdata *gpd = CTX_data_gpencil_data(C); | |||||
| bGPDpalette *palette = NULL; | |||||
| int palette_num = RNA_enum_get(op->ptr, "palette"); | |||||
| /* Get palette or create new one */ | |||||
| if (palette_num == -1) { | |||||
| /* Create palette */ | |||||
| palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true); | |||||
| } | |||||
| else { | |||||
| /* Try to get palette */ | |||||
| palette = BLI_findlink(&gpd->palettes, palette_num); | |||||
| if (palette == NULL) { | |||||
| BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent palette (index = %d)", palette_num); | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| } | } | ||||
| /* notifiers */ | |||||
| /* Set active palette */ | |||||
| BKE_gpencil_palette_setactive(gpd, palette); | |||||
| /* updates */ | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_palette_change(wmOperatorType *ot) | void GPENCIL_OT_sculpt_select(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Change Palette"; | ot->name = "Select Sculpt Brush"; | ||||
| ot->idname = "GPENCIL_OT_palette_change"; | ot->idname = "GPENCIL_OT_sculpt_select"; | ||||
| ot->description = "Change active Grease Pencil palette"; | ot->description = "Select a Grease Pencil sculpt brush"; | ||||
| /* callbacks */ | /* callbacks */ | ||||
| ot->invoke = gp_palette_change_invoke; | ot->exec = gp_sculpt_select_exec; | ||||
| ot->exec = gp_palette_change_exec; | ot->poll = gp_add_poll; | ||||
| ot->poll = gp_active_palette_poll; | |||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* gp palette to use (dynamic enum) */ | /* properties */ | ||||
| ot->prop = RNA_def_enum(ot->srna, "palette", DummyRNA_DEFAULT_items, 0, "Grease Pencil Palette", ""); | RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Sculpt Brush", 0, INT_MAX); | ||||
| RNA_def_enum_funcs(ot->prop, ED_gpencil_palettes_enum_itemf); | |||||
| } | } | ||||
| /* ******************* Lock and hide any color non used in current layer ************************** */ | /* ******************* Convert animation data ************************ */ | ||||
| static int gp_palette_lock_layer_exec(bContext *C, wmOperator *UNUSED(op)) | static int gp_convert_old_palettes_poll(bContext *C) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | /* TODO: need better poll*/ | ||||
| bGPDpalette *palette; | Main *bmain = CTX_data_main(C); | ||||
| if (bmain->gpencil.first) { | |||||
| /* sanity checks */ | return true; | ||||
| if (ELEM(NULL, gpd)) | |||||
| return OPERATOR_CANCELLED; | |||||
| palette = BKE_gpencil_palette_getactive(gpd); | |||||
| if (ELEM(NULL, palette)) | |||||
| return OPERATOR_CANCELLED; | |||||
| /* first lock and hide all colors */ | |||||
| for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { | |||||
| palcolor->flag |= PC_COLOR_LOCKED; | |||||
| palcolor->flag |= PC_COLOR_HIDE; | |||||
| } | } | ||||
| else { | |||||
| /* loop all selected strokes and unlock any color used in active layer */ | return false; | ||||
| for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { | |||||
| /* only editable and visible layers are considered */ | |||||
| if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) && (gpl->flag & GP_LAYER_ACTIVE)) { | |||||
| for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) { | |||||
| /* skip strokes that are invalid for current view */ | |||||
| if (ED_gpencil_stroke_can_use(C, gps) == false) | |||||
| continue; | |||||
| /* unlock/unhide color if not unlocked before */ | |||||
| if (gps->palcolor != NULL) { | |||||
| gps->palcolor->flag &= ~PC_COLOR_LOCKED; | |||||
| gps->palcolor->flag &= ~PC_COLOR_HIDE; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| /* notifiers */ | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void GPENCIL_OT_palette_lock_layer(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Disable Unused Layer Colors"; | |||||
| ot->idname = "GPENCIL_OT_palette_lock_layer"; | |||||
| ot->description = "Lock and hide any color not used in any layer"; | |||||
| /* api callbacks */ | |||||
| ot->exec = gp_palette_lock_layer_exec; | |||||
| ot->poll = gp_active_layer_poll; | |||||
| } | } | ||||
| /* ************************************************ */ | /* convert old animation data to new format */ | ||||
| /* Palette Colors Operators */ | static int gp_convert_old_palettes_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| /* ******************* Add New Palette ************************ */ | |||||
| /* add new palette - wrapper around API */ | |||||
| static int gp_palettecolor_add_exec(bContext *C, wmOperator *op) | |||||
| { | { | ||||
| bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); | Main *bmain = CTX_data_main(C); | ||||
| for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) { | |||||
| /* if there's no existing Grease-Pencil data there, add some */ | BKE_gpencil_move_animdata_to_palettes(C, gpd); | ||||
| if (gpd_ptr == NULL) { | |||||
| BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); | |||||
| return OPERATOR_CANCELLED; | |||||
| } | } | ||||
| if (*gpd_ptr == NULL) | |||||
| *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); | |||||
| /* verify palette */ | |||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(*gpd_ptr); | |||||
| if (palette == NULL) | |||||
| palette = BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true); | |||||
| /* add new palette color now */ | |||||
| BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true); | |||||
| /* notifiers */ | /* notifiers */ | ||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_palettecolor_add(wmOperatorType *ot) | void GPENCIL_OT_convert_old_palettes(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Add Palette Color"; | ot->name = "Convert Old Palettes"; | ||||
| ot->idname = "GPENCIL_OT_palettecolor_add"; | ot->idname = "GPENCIL_OT_convert_old_palettes"; | ||||
| ot->description = "Add new Grease Pencil palette color for the active Grease Pencil data-block"; | ot->description = "Convert old gpencil palettes animation data to blender palettes"; | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* callbacks */ | /* callbacks */ | ||||
| ot->exec = gp_palettecolor_add_exec; | ot->exec = gp_convert_old_palettes_exec; | ||||
| ot->poll = gp_add_poll; | ot->poll = gp_convert_old_palettes_poll; | ||||
| } | } | ||||
| /* ******************* Remove Active Palette color ************************* */ | /* ******************* Convert scene gp data to gp object ************************ */ | ||||
| static int gp_palettecolor_remove_exec(bContext *C, wmOperator *UNUSED(op)) | static int gp_convert_scene_to_object_poll(bContext *C) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | Scene *scene = CTX_data_scene(C); | ||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); | if (scene->gpd) { | ||||
| bGPDpalettecolor *color = BKE_gpencil_palettecolor_getactive(palette); | return true; | ||||
| /* sanity checks */ | |||||
| if (ELEM(NULL, gpd, palette, color)) | |||||
| return OPERATOR_CANCELLED; | |||||
| /* make the palette color before this the new active color | |||||
| * - use the one after if this is the first | |||||
| * - if this is the only color, this naturally becomes NULL | |||||
| */ | |||||
| if (color->prev) | |||||
| BKE_gpencil_palettecolor_setactive(palette, color->prev); | |||||
| else | |||||
| BKE_gpencil_palettecolor_setactive(palette, color->next); | |||||
| /* delete the strokes */ | |||||
| BKE_gpencil_palettecolor_delete_strokes(gpd, color->info); | |||||
| /* delete the palette color now... */ | |||||
| BKE_gpencil_palettecolor_delete(palette, color); | |||||
| /* notifiers */ | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void GPENCIL_OT_palettecolor_remove(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Remove palette color"; | |||||
| ot->idname = "GPENCIL_OT_palettecolor_remove"; | |||||
| ot->description = "Remove active Grease Pencil palette color"; | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| /* callbacks */ | |||||
| ot->exec = gp_palettecolor_remove_exec; | |||||
| ot->poll = gp_active_palettecolor_poll; | |||||
| } | |||||
| /* ********************** Isolate palette color **************************** */ | |||||
| static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); | |||||
| bGPDpalettecolor *active_color = BKE_gpencil_palettecolor_getactive(palette); | |||||
| bGPDpalettecolor *palcolor; | |||||
| int flags = PC_COLOR_LOCKED; | |||||
| bool isolate = false; | |||||
| if (RNA_boolean_get(op->ptr, "affect_visibility")) | |||||
| flags |= PC_COLOR_HIDE; | |||||
| if (ELEM(NULL, gpd, active_color)) { | |||||
| BKE_report(op->reports, RPT_ERROR, "No active color to isolate"); | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| /* Test whether to isolate or clear all flags */ | |||||
| for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { | |||||
| /* Skip if this is the active one */ | |||||
| if (palcolor == active_color) | |||||
| continue; | |||||
| /* If the flags aren't set, that means that the color is | |||||
| * not alone, so we have some colors to isolate still | |||||
| */ | |||||
| if ((palcolor->flag & flags) == 0) { | |||||
| isolate = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| /* Set/Clear flags as appropriate */ | |||||
| if (isolate) { | |||||
| /* Set flags on all "other" colors */ | |||||
| for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { | |||||
| if (palcolor == active_color) | |||||
| continue; | |||||
| else | |||||
| palcolor->flag |= flags; | |||||
| } | |||||
| } | } | ||||
| else { | else { | ||||
| /* Clear flags - Restore everything else */ | return false; | ||||
| for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { | |||||
| palcolor->flag &= ~flags; | |||||
| } | |||||
| } | } | ||||
| /* notifiers */ | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void GPENCIL_OT_palettecolor_isolate(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Isolate Palette Color"; | |||||
| ot->idname = "GPENCIL_OT_palettecolor_isolate"; | |||||
| ot->description = "Toggle whether the active color is the only one that is editable and/or visible"; | |||||
| /* callbacks */ | |||||
| ot->exec = gp_isolate_palettecolor_exec; | |||||
| ot->poll = gp_active_palettecolor_poll; | |||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| /* properties */ | |||||
| RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility", "In addition to toggling " | |||||
| "the editability, also affect the visibility"); | |||||
| } | } | ||||
| /* *********************** Hide Palette colors ******************************** */ | /* convert scene datablock to gpencil object */ | ||||
| static int gp_convert_scene_to_object_exec(bContext *C, wmOperator *UNUSED(op)) | |||||
| static int gp_palettecolor_hide_exec(bContext *C, wmOperator *op) | |||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | Scene *scene = CTX_data_scene(C); | ||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); | ToolSettings *ts = CTX_data_tool_settings(C); | ||||
| bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); | bGPdata *gpd = scene->gpd; | ||||
| float loc[3] = { 0.0f, 0.0f, 0.0f }; | |||||
| bool unselected = RNA_boolean_get(op->ptr, "unselected"); | |||||
| /* sanity checks */ | |||||
| if (ELEM(NULL, gpd, palette, palcolor)) | |||||
| return OPERATOR_CANCELLED; | |||||
| if (unselected) { | Object *ob = ED_add_gpencil_object(C, scene, loc); /* always in origin */ | ||||
| bGPDpalettecolor *color; | ob->gpd = gpd; | ||||
| scene->gpd = NULL; | |||||
| /* hide unselected */ | /* set grease pencil mode to object */ | ||||
| for (color = palette->colors.first; color; color = color->next) { | ts->gpencil_src = GP_TOOL_SOURCE_OBJECT; | ||||
| if (color != palcolor) { | |||||
| color->flag |= PC_COLOR_HIDE; | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* hide selected/active */ | |||||
| palcolor->flag |= PC_COLOR_HIDE; | |||||
| } | |||||
| /* notifiers */ | /* notifiers */ | ||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | BKE_gpencil_batch_cache_dirty(gpd); | ||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); | |||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_palettecolor_hide(wmOperatorType *ot) | void GPENCIL_OT_convert_scene_to_object(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Hide Color(s)"; | ot->name = "Convert Scene Datablock to gpencil Object"; | ||||
| ot->idname = "GPENCIL_OT_palettecolor_hide"; | ot->idname = "GPENCIL_OT_convert_scene_to_object"; | ||||
| ot->description = "Hide selected/unselected Grease Pencil colors"; | ot->description = "Convert scene grease pencil datablock to gpencil object"; | ||||
| /* callbacks */ | |||||
| ot->exec = gp_palettecolor_hide_exec; | |||||
| ot->poll = gp_active_palettecolor_poll; /* NOTE: we need an active color to play with */ | |||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* props */ | |||||
| RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected colors"); | |||||
| } | |||||
| /* ********************** Show All Colors ***************************** */ | |||||
| /* poll callback for showing colors */ | |||||
| static int gp_palettecolor_reveal_poll(bContext *C) | |||||
| { | |||||
| return ED_gpencil_data_get_active(C) != NULL; | |||||
| } | |||||
| static int gp_palettecolor_reveal_exec(bContext *C, wmOperator *UNUSED(op)) | |||||
| { | |||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); | |||||
| bGPDpalettecolor *palcolor; | |||||
| /* sanity checks */ | |||||
| if (ELEM(NULL, gpd, palette)) | |||||
| return OPERATOR_CANCELLED; | |||||
| /* make all colors visible */ | |||||
| for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { | |||||
| palcolor->flag &= ~PC_COLOR_HIDE; | |||||
| } | |||||
| /* notifiers */ | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void GPENCIL_OT_palettecolor_reveal(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Show All Colors"; | |||||
| ot->idname = "GPENCIL_OT_palettecolor_reveal"; | |||||
| ot->description = "Unhide all hidden Grease Pencil palette colors"; | |||||
| /* callbacks */ | /* callbacks */ | ||||
| ot->exec = gp_palettecolor_reveal_exec; | ot->exec = gp_convert_scene_to_object_exec; | ||||
| ot->poll = gp_palettecolor_reveal_poll; | ot->poll = gp_convert_scene_to_object_poll; | ||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| } | } | ||||
| /* ***************** Lock/Unlock All Palette colors ************************ */ | /*********************** Vertex Groups ***********************************/ | ||||
| static int gp_palettecolor_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) | static int gpencil_vertex_group_poll(bContext *C) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | Object *ob = CTX_data_active_object(C); | ||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); | |||||
| bGPDpalettecolor *palcolor; | |||||
| /* sanity checks */ | |||||
| if (ELEM(NULL, gpd, palette)) | |||||
| return OPERATOR_CANCELLED; | |||||
| /* make all layers non-editable */ | if ((ob) && (ob->type == OB_GPENCIL)) { | ||||
| for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { | return (!ID_IS_LINKED_DATABLOCK(ob) && | ||||
| palcolor->flag |= PC_COLOR_LOCKED; | !ID_IS_LINKED_DATABLOCK(ob->gpd) && | ||||
| ob->defbase.first && | |||||
| ((ob->mode == OB_MODE_GPENCIL_EDIT) || (ob->mode == OB_MODE_GPENCIL_SCULPT))); | |||||
| } | |||||
| else { | |||||
| return false; | |||||
| } | } | ||||
| /* notifiers */ | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void GPENCIL_OT_palettecolor_lock_all(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Lock All Colors"; | |||||
| ot->idname = "GPENCIL_OT_palettecolor_lock_all"; | |||||
| ot->description = "Lock all Grease Pencil colors to prevent them from being accidentally modified"; | |||||
| /* callbacks */ | |||||
| ot->exec = gp_palettecolor_lock_all_exec; | |||||
| ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */ | |||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| } | } | ||||
| /* -------------------------- */ | static int gpencil_vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| static int gp_palettecolor_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) | |||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | ToolSettings *ts = CTX_data_tool_settings(C); | ||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); | Object *ob = CTX_data_active_object(C); | ||||
| bGPDpalettecolor *palcolor; | |||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, gpd, palette)) | if (ELEM(NULL, ts, ob, ob->gpd)) | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| /* make all layers editable again*/ | ED_gpencil_vgroup_assign(C, ob, ts->vgroup_weight); | ||||
| for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { | |||||
| palcolor->flag &= ~PC_COLOR_LOCKED; | |||||
| } | |||||
| /* notifiers */ | /* notifiers */ | ||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | BKE_gpencil_batch_cache_dirty(ob->gpd); | ||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); | |||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_palettecolor_unlock_all(wmOperatorType *ot) | void GPENCIL_OT_vertex_group_assign(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Unlock All Colors"; | ot->name = "Assign to Vertex Group"; | ||||
| ot->idname = "GPENCIL_OT_palettecolor_unlock_all"; | ot->idname = "GPENCIL_OT_vertex_group_assign"; | ||||
| ot->description = "Unlock all Grease Pencil colors so that they can be edited"; | ot->description = "Assign the selected vertices to the active vertex group"; | ||||
| /* callbacks */ | /* api callbacks */ | ||||
| ot->exec = gp_palettecolor_unlock_all_exec; | ot->poll = gpencil_vertex_group_poll; | ||||
| ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */ | ot->exec = gpencil_vertex_group_assign_exec; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ******************* Move Color Up/Down ************************** */ | /* remove point from vertex group */ | ||||
| static int gpencil_vertex_group_remove_from_exec(bContext *C, wmOperator *UNUSED(op)) | |||||
| enum { | |||||
| GP_COLOR_MOVE_UP = -1, | |||||
| GP_COLOR_MOVE_DOWN = 1 | |||||
| }; | |||||
| static int gp_palettecolor_move_exec(bContext *C, wmOperator *op) | |||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | Object *ob = CTX_data_active_object(C); | ||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); | |||||
| bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); | |||||
| int direction = RNA_enum_get(op->ptr, "direction"); | |||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, gpd, palette, palcolor)) | if (ELEM(NULL, ob, ob->gpd)) | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| /* up or down? */ | ED_gpencil_vgroup_remove(C, ob); | ||||
| if (direction == GP_COLOR_MOVE_UP) { | |||||
| /* up */ | |||||
| BLI_remlink(&palette->colors, palcolor); | |||||
| BLI_insertlinkbefore(&palette->colors, palcolor->prev, palcolor); | |||||
| } | |||||
| else if (direction == GP_COLOR_MOVE_DOWN) { | |||||
| /* down */ | |||||
| BLI_remlink(&palette->colors, palcolor); | |||||
| BLI_insertlinkafter(&palette->colors, palcolor->next, palcolor); | |||||
| } | |||||
| else { | |||||
| BLI_assert(0); | |||||
| } | |||||
| /* notifiers */ | /* notifiers */ | ||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | BKE_gpencil_batch_cache_dirty(ob->gpd); | ||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); | |||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_palettecolor_move(wmOperatorType *ot) | void GPENCIL_OT_vertex_group_remove_from(wmOperatorType *ot) | ||||
| { | { | ||||
| static const EnumPropertyItem slot_move[] = { | |||||
| {GP_COLOR_MOVE_UP, "UP", 0, "Up", ""}, | |||||
| {GP_COLOR_MOVE_DOWN, "DOWN", 0, "Down", ""}, | |||||
| {0, NULL, 0, NULL, NULL} | |||||
| }; | |||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Move Palette color"; | ot->name = "Remove from Vertex Group"; | ||||
| ot->idname = "GPENCIL_OT_palettecolor_move"; | ot->idname = "GPENCIL_OT_vertex_group_remove_from"; | ||||
| ot->description = "Move the active Grease Pencil palette color up/down in the list"; | ot->description = "Remove the selected vertices from active or all vertex group(s)"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->exec = gp_palettecolor_move_exec; | ot->poll = gpencil_vertex_group_poll; | ||||
| ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */ | ot->exec = gpencil_vertex_group_remove_from_exec; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_COLOR_MOVE_UP, "Direction", ""); | |||||
| } | } | ||||
| /* ***************** Select all strokes using Palette color ************************ */ | static int gpencil_vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| static int gp_palettecolor_select_exec(bContext *C, wmOperator *UNUSED(op)) | |||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | Object *ob = CTX_data_active_object(C); | ||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); | |||||
| bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); | |||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, gpd, palette, palcolor)) | if (ELEM(NULL, ob, ob->gpd)) | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| /* read all strokes and select*/ | ED_gpencil_vgroup_select(C, ob); | ||||
| for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { | |||||
| /* only editable and visible layers are considered */ | |||||
| if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { | |||||
| /* verify something to do */ | |||||
| for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) { | |||||
| /* skip strokes that are invalid for current view */ | |||||
| if (ED_gpencil_stroke_can_use(C, gps) == false) | |||||
| continue; | |||||
| /* check if the color is editable */ | |||||
| if (ED_gpencil_stroke_color_use(gpl, gps) == false) | |||||
| continue; | |||||
| /* select */ | |||||
| if (strcmp(palcolor->info, gps->colorname) == 0) { | |||||
| bGPDspoint *pt; | |||||
| int i; | |||||
| gps->flag |= GP_STROKE_SELECT; | |||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | |||||
| pt->flag |= GP_SPOINT_SELECT; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /* notifiers */ | /* notifiers */ | ||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | BKE_gpencil_batch_cache_dirty(ob->gpd); | ||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); | |||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_palettecolor_select(wmOperatorType *ot) | void GPENCIL_OT_vertex_group_select(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Select Color"; | ot->name = "Select Vertex Group"; | ||||
| ot->idname = "GPENCIL_OT_palettecolor_select"; | ot->idname = "GPENCIL_OT_vertex_group_select"; | ||||
| ot->description = "Select all Grease Pencil strokes using current color"; | ot->description = "Select all the vertices assigned to the active vertex group"; | ||||
| /* callbacks */ | /* api callbacks */ | ||||
| ot->exec = gp_palettecolor_select_exec; | ot->poll = gpencil_vertex_group_poll; | ||||
| ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */ | ot->exec = gpencil_vertex_group_select_exec; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ***************** Copy Palette color ************************ */ | static int gpencil_vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| static int gp_palettecolor_copy_exec(bContext *C, wmOperator *UNUSED(op)) | |||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | Object *ob = CTX_data_active_object(C); | ||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); | |||||
| bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); | |||||
| bGPDpalettecolor *newcolor; | |||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, gpd, palette, palcolor)) | if (ELEM(NULL, ob, ob->gpd)) | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| /* create a new color and duplicate data */ | ED_gpencil_vgroup_deselect(C, ob); | ||||
| newcolor = BKE_gpencil_palettecolor_addnew(palette, palcolor->info, true); | |||||
| copy_v4_v4(newcolor->color, palcolor->color); | |||||
| copy_v4_v4(newcolor->fill, palcolor->fill); | |||||
| newcolor->flag = palcolor->flag; | |||||
| /* notifiers */ | /* notifiers */ | ||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | BKE_gpencil_batch_cache_dirty(ob->gpd); | ||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); | |||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_palettecolor_copy(wmOperatorType *ot) | void GPENCIL_OT_vertex_group_deselect(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Copy Color"; | ot->name = "Deselect Vertex Group"; | ||||
| ot->idname = "GPENCIL_OT_palettecolor_copy"; | ot->idname = "GPENCIL_OT_vertex_group_deselect"; | ||||
| ot->description = "Copy current Grease Pencil palette color"; | ot->description = "Deselect all selected vertices assigned to the active vertex group"; | ||||
| /* callbacks */ | /* api callbacks */ | ||||
| ot->exec = gp_palettecolor_copy_exec; | ot->poll = gpencil_vertex_group_poll; | ||||
| ot->poll = gp_active_palettecolor_poll; | ot->exec = gpencil_vertex_group_deselect_exec; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| Context not available. | |||||