diff options
6 files changed, 221 insertions, 51 deletions
diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py index 69720a6c54b..d88c9a3502d 100644 --- a/release/scripts/startup/bl_ui/properties_data_gpencil.py +++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py @@ -113,7 +113,8 @@ class GPENCIL_MT_layer_context_menu(Menu): layout.operator("gpencil.layer_merge", icon='SORT_ASC', text="Merge Down") layout.separator() - layout.menu("VIEW3D_MT_gpencil_copy_layer") + layout.menu("VIEW3D_MT_gpencil_append_active_layer") + layout.menu("VIEW3D_MT_gpencil_append_all_layers") class DATA_PT_gpencil_layers(DataButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/properties_material_gpencil.py b/release/scripts/startup/bl_ui/properties_material_gpencil.py index 6a5c000116f..ed5863b463a 100644 --- a/release/scripts/startup/bl_ui/properties_material_gpencil.py +++ b/release/scripts/startup/bl_ui/properties_material_gpencil.py @@ -53,6 +53,10 @@ class GPENCIL_MT_material_context_menu(Menu): layout.operator("gpencil.material_to_vertex_color", text="Convert Materials to Vertex Color") layout.operator("gpencil.extract_palette_vertex", text="Extract Palette from Vertex Color") + layout.separator() + layout.menu("VIEW3D_MT_gpencil_append_active_material") + layout.menu("VIEW3D_MT_gpencil_append_all_materials") + class GPENCIL_UL_matslots(UIList): def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index): diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index bdc924e3197..4b06a2df3a0 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -4956,26 +4956,73 @@ class VIEW3D_MT_assign_material(Menu): icon='LAYER_ACTIVE' if mat == mat_active else 'BLANK1').material = mat.name -class VIEW3D_MT_gpencil_copy_layer(Menu): - bl_label = "Copy Layer to Object" +def gpencil_layer_append_menu_items(context, layout, only_active): + done = False + view_layer = context.view_layer + obact = context.active_object + gpl = context.active_gpencil_layer + + done = False + if gpl is not None: + for ob in view_layer.objects: + if ob.type == 'GPENCIL' and ob != obact: + op = layout.operator("gpencil.layer_duplicate_object", text=ob.name) + op.object = ob.name + op.only_active = only_active + done = True + + if done is False: + layout.label(text="No destination object", icon='ERROR') + else: + layout.label(text="No layer to copy", icon='ERROR') + + +class VIEW3D_MT_gpencil_append_active_layer(Menu): + bl_label = "Append Active Layer to Object" def draw(self, context): layout = self.layout - view_layer = context.view_layer - obact = context.active_object - gpl = context.active_gpencil_layer - - done = False - if gpl is not None: - for ob in view_layer.objects: - if ob.type == 'GPENCIL' and ob != obact: - layout.operator("gpencil.layer_duplicate_object", text=ob.name).object = ob.name - done = True - - if done is False: - layout.label(text="No destination object", icon='ERROR') - else: - layout.label(text="No layer to copy", icon='ERROR') + gpencil_layer_append_menu_items(context, layout, True) + + +class VIEW3D_MT_gpencil_append_all_layers(Menu): + bl_label = "Append All Layers to Object" + + def draw(self, context): + layout = self.layout + gpencil_layer_append_menu_items(context, layout, False) + + +def gpencil_material_menu_items(context, layout, only_selected): + done = False + view_layer = context.view_layer + obact = context.active_object + + for ob in view_layer.objects: + if ob.type == 'GPENCIL' and ob != obact: + op = layout.operator("gpencil.materials_append_to_object", text=ob.name) + op.object = ob.name + op.only_selected = only_selected + done = True + + if done is False: + layout.label(text="No destination object", icon='ERROR') + + +class VIEW3D_MT_gpencil_append_active_material(Menu): + bl_label = "Append Active Material to Object" + + def draw(self, context): + layout = self.layout + gpencil_material_menu_items(context, layout, True) + + +class VIEW3D_MT_gpencil_append_all_materials(Menu): + bl_label = "Append All Materials to Object" + + def draw(self, context): + layout = self.layout + gpencil_material_menu_items(context, layout, False) class VIEW3D_MT_edit_gpencil(Menu): @@ -7642,7 +7689,10 @@ classes = ( VIEW3D_MT_weight_gpencil, VIEW3D_MT_gpencil_animation, VIEW3D_MT_gpencil_simplify, - VIEW3D_MT_gpencil_copy_layer, + VIEW3D_MT_gpencil_append_active_layer, + VIEW3D_MT_gpencil_append_all_layers, + VIEW3D_MT_gpencil_append_active_material, + VIEW3D_MT_gpencil_append_all_materials, VIEW3D_MT_gpencil_autoweights, VIEW3D_MT_gpencil_edit_context_menu, VIEW3D_MT_edit_curve, diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index c93fcb9eb8c..c5f094e030a 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -557,6 +557,7 @@ static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op) if (name[0] == '\0') { return OPERATOR_CANCELLED; } + const bool only_active = RNA_boolean_get(op->ptr, "only_active"); Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name); @@ -564,10 +565,10 @@ static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op) Object *ob_src = CTX_data_active_object(C); bGPdata *gpd_src = (bGPdata *)ob_src->data; - bGPDlayer *gpl_src = BKE_gpencil_layer_active_get(gpd_src); + bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd_src); /* Sanity checks. */ - if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) { + if (ELEM(NULL, gpd_src, ob_dst)) { return OPERATOR_CANCELLED; } /* Cannot copy itself and check destination type. */ @@ -576,47 +577,55 @@ static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op) } bGPdata *gpd_dst = (bGPdata *)ob_dst->data; + /* Disable destination active layer to keep order. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_dst->layers) { + gpl->flag &= ~GP_LAYER_ACTIVE; + } - /* Create new layer. */ - bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true); - /* Need to copy some variables (not all). */ - gpl_dst->onion_flag = gpl_src->onion_flag; - gpl_dst->thickness = gpl_src->thickness; - gpl_dst->line_change = gpl_src->line_change; - copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor); - gpl_dst->opacity = gpl_src->opacity; - - /* Create all frames. */ - LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { - - if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) { + LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) { + if ((only_active) && (gpl_src != gpl_active)) { continue; } + /* Create new layer. */ + bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true); + /* Need to copy some variables (not all). */ + gpl_dst->onion_flag = gpl_src->onion_flag; + gpl_dst->thickness = gpl_src->thickness; + gpl_dst->line_change = gpl_src->line_change; + copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor); + gpl_dst->opacity = gpl_src->opacity; - /* Create new frame. */ - bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum); + /* Create all frames. */ + LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { - /* Copy strokes. */ - LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) { + if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) { + continue; + } - /* Make copy of source stroke. */ - bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true); + /* Create new frame. */ + bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum); - /* Check if material is in destination object, - * otherwise add the slot with the material. */ - Material *ma_src = BKE_object_material_get(ob_src, gps_src->mat_nr + 1); - if (ma_src != NULL) { - int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src); + /* Copy strokes. */ + LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) { - /* Reassign the stroke material to the right slot in destination object. */ - gps_dst->mat_nr = idx; - } + /* Make copy of source stroke. */ + bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true); + + /* Check if material is in destination object, + * otherwise add the slot with the material. */ + Material *ma_src = BKE_object_material_get(ob_src, gps_src->mat_nr + 1); + if (ma_src != NULL) { + int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src); - /* Add new stroke to frame. */ - BLI_addtail(&gpf_dst->strokes, gps_dst); + /* Reassign the stroke material to the right slot in destination object. */ + gps_dst->mat_nr = idx; + } + + /* Add new stroke to frame. */ + BLI_addtail(&gpf_dst->strokes, gps_dst); + } } } - /* notifiers */ DEG_id_tag_update(&gpd_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); @@ -628,6 +637,8 @@ static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op) void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot) { + PropertyRNA *prop; + static const EnumPropertyItem copy_mode[] = { {GP_LAYER_COPY_OBJECT_ALL_FRAME, "ALL", 0, "All Frames", ""}, {GP_LAYER_COPY_OBJECT_ACT_FRAME, "ACTIVE", 0, "Active Frame", ""}, @@ -651,6 +662,13 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot) RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE); RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_COPY_OBJECT_ALL_FRAME, "Mode", ""); + + prop = RNA_def_boolean(ot->srna, + "only_active", + true, + "Only Active", + "Append only active Layer, uncheck to append all layers"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /* ********************* Duplicate Frame ************************** */ @@ -3589,6 +3607,101 @@ void GPENCIL_OT_set_active_material(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* ********************* Append Materials in a new object ************************** */ +static bool gpencil_materials_append_to_object_poll(bContext *C) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = CTX_data_active_object(C); + if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + return false; + } + short *totcolp = BKE_object_material_len_p(ob); + if (*totcolp == 0) { + return false; + } + + /* check there are more grease pencil objects */ + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { + if ((base->object != ob) && (base->object->type == OB_GPENCIL)) { + return true; + } + } + + return false; +} + +static int gpencil_materials_append_to_object_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + char name[MAX_ID_NAME - 2]; + RNA_string_get(op->ptr, "object", name); + + if (name[0] == '\0') { + return OPERATOR_CANCELLED; + } + const bool only_selected = RNA_boolean_get(op->ptr, "only_selected"); + + Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name); + Object *ob_src = CTX_data_active_object(C); + Material *ma_active = BKE_gpencil_material(ob_src, ob_src->actcol); + + /* Sanity checks. */ + if (ELEM(NULL, ob_src, ob_dst)) { + return OPERATOR_CANCELLED; + } + /* Cannot copy itself and check destination type. */ + if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) { + return OPERATOR_CANCELLED; + } + + /* Duplicate materials. */ + for (short i = 0; i < ob_src->totcol; i++) { + Material *ma_src = BKE_object_material_get(ob_src, i + 1); + if (only_selected && ma_src != ma_active) { + continue; + } + + if (ma_src != NULL) { + BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src); + } + } + + /* notifiers */ + DEG_id_tag_update(&ob_dst->id, ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_materials_append_to_object(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Append Materials to New Object"; + ot->idname = "GPENCIL_OT_materials_append_to_object"; + ot->description = "Append Materials of the active Grease Pencil to other object"; + + /* callbacks */ + ot->exec = gpencil_materials_append_to_object_exec; + ot->poll = gpencil_materials_append_to_object_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_string( + ot->srna, "object", NULL, MAX_ID_NAME - 2, "Object", "Name of the destination object"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_boolean(ot->srna, + "only_selected", + true, + "Only Selected", + "Append only selected material, uncheck to append all materials"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); +} + /* Parent GPencil object to Lattice */ bool ED_gpencil_add_lattice_modifier(const bContext *C, ReportList *reports, diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 09200125cb7..cce56acd3e4 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -538,6 +538,7 @@ void GPENCIL_OT_material_lock_unused(struct wmOperatorType *ot); void GPENCIL_OT_material_select(struct wmOperatorType *ot); void GPENCIL_OT_material_set(struct wmOperatorType *ot); void GPENCIL_OT_set_active_material(struct wmOperatorType *ot); +void GPENCIL_OT_materials_append_to_object(struct wmOperatorType *ot); /* convert old 2.7 files to 2.8 */ void GPENCIL_OT_convert_old_files(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 7d454eb3be1..6ac1161bff8 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -651,6 +651,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_material_to_vertex_color); WM_operatortype_append(GPENCIL_OT_extract_palette_vertex); + WM_operatortype_append(GPENCIL_OT_materials_append_to_object); WM_operatortype_append(GPENCIL_OT_transform_fill); WM_operatortype_append(GPENCIL_OT_reset_transform_fill); |