Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/gpencil/gpencil_select.c
| Show All 37 Lines | |||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_ghash.h" | #include "BLI_ghash.h" | ||||
| #include "BLI_lasso_2d.h" | #include "BLI_lasso_2d.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_math_vector.h" | #include "BLI_math_vector.h" | ||||
| #include "DNA_gpencil_types.h" | #include "DNA_gpencil_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_space_types.h" | |||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_gpencil.h" | #include "BKE_gpencil.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "RNA_define.h" | #include "RNA_define.h" | ||||
| #include "UI_view2d.h" | #include "UI_view2d.h" | ||||
| #include "ED_gpencil.h" | #include "ED_gpencil.h" | ||||
| #include "DEG_depsgraph.h" | |||||
| #include "DEG_depsgraph_query.h" | |||||
| #include "gpencil_intern.h" | #include "gpencil_intern.h" | ||||
| /* ********************************************** */ | /* ********************************************** */ | ||||
| /* Polling callbacks */ | /* Polling callbacks */ | ||||
| static int gpencil_select_poll(bContext *C) | static int gpencil_select_poll(bContext *C) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | bGPdata *gpd = ED_gpencil_data_get_active(C); | ||||
| /* we just need some visible strokes, and to be in editmode */ | /* we just need some visible strokes, and to be in editmode or other modes only to catch event */ | ||||
| if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) { | if (GPENCIL_ANY_MODE(gpd)) { | ||||
| /* TODO: include a check for visible strokes? */ | /* TODO: include a check for visible strokes? */ | ||||
| if (gpd->layers.first) | if (gpd->layers.first) | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* ********************************************** */ | /* ********************************************** */ | ||||
| /* Select All Operator */ | /* Select All Operator */ | ||||
| static int gpencil_select_all_exec(bContext *C, wmOperator *op) | static int gpencil_select_all_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | bGPdata *gpd = ED_gpencil_data_get_active(C); | ||||
| int action = RNA_enum_get(op->ptr, "action"); | int action = RNA_enum_get(op->ptr, "action"); | ||||
| if (gpd == NULL) { | if (gpd == NULL) { | ||||
| BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); | BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* if not edit/sculpt mode, the event is catched but not processed */ | |||||
| if (GPENCIL_NONE_EDIT_MODE(gpd)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| /* for "toggle", test for existing selected strokes */ | /* for "toggle", test for existing selected strokes */ | ||||
| if (action == SEL_TOGGLE) { | if (action == SEL_TOGGLE) { | ||||
| action = SEL_SELECT; | action = SEL_SELECT; | ||||
| CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | ||||
| { | { | ||||
| if (gps->flag & GP_STROKE_SELECT) { | if (gps->flag & GP_STROKE_SELECT) { | ||||
| action = SEL_DESELECT; | action = SEL_DESELECT; | ||||
| ▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | ||||
| gps->flag |= GP_STROKE_SELECT; | gps->flag |= GP_STROKE_SELECT; | ||||
| else | else | ||||
| gps->flag &= ~GP_STROKE_SELECT; | gps->flag &= ~GP_STROKE_SELECT; | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| } | } | ||||
| /* updates */ | /* updates */ | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_select_all(wmOperatorType *ot) | void GPENCIL_OT_select_all(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "(De)select All Strokes"; | ot->name = "(De)select All Strokes"; | ||||
| Show All 17 Lines | |||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | bGPdata *gpd = ED_gpencil_data_get_active(C); | ||||
| if (gpd == NULL) { | if (gpd == NULL) { | ||||
| BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); | BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* if not edit/sculpt mode, the event is catched but not processed */ | |||||
| if (GPENCIL_NONE_EDIT_MODE(gpd)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| /* select all points in selected strokes */ | /* select all points in selected strokes */ | ||||
| CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | ||||
| { | { | ||||
| if (gps->flag & GP_STROKE_SELECT) { | if (gps->flag & GP_STROKE_SELECT) { | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| int i; | int i; | ||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | ||||
| pt->flag |= GP_SPOINT_SELECT; | pt->flag |= GP_SPOINT_SELECT; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| /* updates */ | /* updates */ | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_select_linked(wmOperatorType *ot) | void GPENCIL_OT_select_linked(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Select Linked"; | ot->name = "Select Linked"; | ||||
| ot->idname = "GPENCIL_OT_select_linked"; | ot->idname = "GPENCIL_OT_select_linked"; | ||||
| ot->description = "Select all points in same strokes as already selected points"; | ot->description = "Select all points in same strokes as already selected points"; | ||||
| /* callbacks */ | /* callbacks */ | ||||
| ot->exec = gpencil_select_linked_exec; | ot->exec = gpencil_select_linked_exec; | ||||
| ot->poll = gpencil_select_poll; | ot->poll = gpencil_select_poll; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ********************************************** */ | /* ********************************************** */ | ||||
| /* Select Alternate */ | |||||
| static int gpencil_select_alternate_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| const bool unselect_ends = RNA_boolean_get(op->ptr, "unselect_ends"); | |||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| if (gpd == NULL) { | |||||
| BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| /* if not edit/sculpt mode, the event is catched but not processed */ | |||||
| if (GPENCIL_NONE_EDIT_MODE(gpd)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| /* select all points in selected strokes */ | |||||
| CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | |||||
| { | |||||
| if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) { | |||||
| bGPDspoint *pt; | |||||
| int row = 0; | |||||
| int start = 0; | |||||
| if (unselect_ends) { | |||||
| start = 1; | |||||
| } | |||||
| for (int i = start; i < gps->totpoints; i++) { | |||||
| pt = &gps->points[i]; | |||||
| if ((row % 2) == 0) { | |||||
| pt->flag |= GP_SPOINT_SELECT; | |||||
| } | |||||
| else { | |||||
| pt->flag &= ~GP_SPOINT_SELECT; | |||||
| } | |||||
| row++; | |||||
| } | |||||
| /* unselect start and end points */ | |||||
| if (unselect_ends) { | |||||
| pt = &gps->points[0]; | |||||
| pt->flag &= ~GP_SPOINT_SELECT; | |||||
| pt = &gps->points[gps->totpoints - 1]; | |||||
| pt->flag &= ~GP_SPOINT_SELECT; | |||||
| } | |||||
| } | |||||
| } | |||||
| CTX_DATA_END; | |||||
| /* updates */ | |||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void GPENCIL_OT_select_alternate(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Alternated"; | |||||
| ot->idname = "GPENCIL_OT_select_alternate"; | |||||
| ot->description = "Select alternative points in same strokes as already selected points"; | |||||
| /* callbacks */ | |||||
| ot->exec = gpencil_select_alternate_exec; | |||||
| ot->poll = gpencil_select_poll; | |||||
| /* flags */ | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| /* properties */ | |||||
| RNA_def_boolean(ot->srna, "unselect_ends", true, "Unselect Ends", "Do not select the first and last point of the stroke"); | |||||
| } | |||||
| /* ********************************************** */ | |||||
| /* Select Grouped */ | /* Select Grouped */ | ||||
| typedef enum eGP_SelectGrouped { | typedef enum eGP_SelectGrouped { | ||||
| /* Select strokes in the same layer */ | /* Select strokes in the same layer */ | ||||
| GP_SEL_SAME_LAYER = 0, | GP_SEL_SAME_LAYER = 0, | ||||
| /* Select strokes with the same color */ | /* Select strokes with the same color */ | ||||
| GP_SEL_SAME_COLOR = 1, | GP_SEL_SAME_COLOR = 1, | ||||
| /* TODO: All with same prefix - Useful for isolating all layers for a particular character for instance */ | /* TODO: All with same prefix - Useful for isolating all layers for a particular character for instance */ | ||||
| /* TODO: All with same appearance - colour/opacity/volumetric/fills ? */ | /* TODO: All with same appearance - colour/opacity/volumetric/fills ? */ | ||||
| } eGP_SelectGrouped; | } eGP_SelectGrouped; | ||||
| /* ----------------------------------- */ | /* ----------------------------------- */ | ||||
| /* On each visible layer, check for selected strokes - if found, select all others */ | /* On each visible layer, check for selected strokes - if found, select all others */ | ||||
| static void gp_select_same_layer(bContext *C) | static void gp_select_same_layer(bContext *C) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | Depsgraph *depsgraph = CTX_data_depsgraph(C); | ||||
| int cfra_eval = (int)DEG_get_ctime(depsgraph); | |||||
| CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) | CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) | ||||
| { | { | ||||
| bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0); | bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0); | ||||
| bGPDstroke *gps; | bGPDstroke *gps; | ||||
| bool found = false; | bool found = false; | ||||
| if (gpf == NULL) | if (gpf == NULL) | ||||
| continue; | continue; | ||||
| /* Search for a selected stroke */ | /* Search for a selected stroke */ | ||||
| for (gps = gpf->strokes.first; gps; gps = gps->next) { | for (gps = gpf->strokes.first; gps; gps = gps->next) { | ||||
| Show All 22 Lines | CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| } | } | ||||
| /* Select all strokes with same colors as selected ones */ | /* Select all strokes with same colors as selected ones */ | ||||
| static void gp_select_same_color(bContext *C) | static void gp_select_same_color(bContext *C) | ||||
| { | { | ||||
| /* First, build set containing all the colors of selected strokes | /* First, build set containing all the colors of selected strokes */ | ||||
| * - We use the palette names, so that we can select all strokes with one | |||||
| * (potentially missing) color, and remap them to something else | |||||
| */ | |||||
| GSet *selected_colors = BLI_gset_str_new("GP Selected Colors"); | GSet *selected_colors = BLI_gset_str_new("GP Selected Colors"); | ||||
| CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | ||||
| { | { | ||||
| if (gps->flag & GP_STROKE_SELECT) { | if (gps->flag & GP_STROKE_SELECT) { | ||||
| /* add instead of insert here, otherwise the uniqueness check gets skipped, | /* add instead of insert here, otherwise the uniqueness check gets skipped, | ||||
| * and we get many duplicate entries... | * and we get many duplicate entries... | ||||
| */ | */ | ||||
| BLI_gset_add(selected_colors, gps->colorname); | BLI_gset_add(selected_colors, &gps->mat_nr); | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| /* Second, select any visible stroke that uses these colors */ | /* Second, select any visible stroke that uses these colors */ | ||||
| CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | ||||
| { | { | ||||
| if (BLI_gset_haskey(selected_colors, gps->colorname)) { | if (BLI_gset_haskey(selected_colors, &gps->mat_nr)) { | ||||
| /* select this stroke */ | /* select this stroke */ | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| int i; | int i; | ||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | ||||
| pt->flag |= GP_SPOINT_SELECT; | pt->flag |= GP_SPOINT_SELECT; | ||||
| } | } | ||||
| gps->flag |= GP_STROKE_SELECT; | gps->flag |= GP_STROKE_SELECT; | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| /* free memomy */ | |||||
| if (selected_colors != NULL) { | |||||
| BLI_gset_free(selected_colors, NULL); | |||||
| } | |||||
| } | } | ||||
| /* ----------------------------------- */ | /* ----------------------------------- */ | ||||
| static int gpencil_select_grouped_exec(bContext *C, wmOperator *op) | static int gpencil_select_grouped_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| eGP_SelectGrouped mode = RNA_enum_get(op->ptr, "type"); | eGP_SelectGrouped mode = RNA_enum_get(op->ptr, "type"); | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| /* if not edit/sculpt mode, the event is catched but not processed */ | |||||
| if (GPENCIL_NONE_EDIT_MODE(gpd)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| switch (mode) { | switch (mode) { | ||||
| case GP_SEL_SAME_LAYER: | case GP_SEL_SAME_LAYER: | ||||
| gp_select_same_layer(C); | gp_select_same_layer(C); | ||||
| break; | break; | ||||
| case GP_SEL_SAME_COLOR: | case GP_SEL_SAME_COLOR: | ||||
| gp_select_same_color(C); | gp_select_same_color(C); | ||||
| break; | break; | ||||
| default: | default: | ||||
| BLI_assert(!"unhandled select grouped gpencil mode"); | BLI_assert(!"unhandled select grouped gpencil mode"); | ||||
| break; | break; | ||||
| } | } | ||||
| /* updates */ | /* updates */ | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_select_grouped(wmOperatorType *ot) | void GPENCIL_OT_select_grouped(wmOperatorType *ot) | ||||
| { | { | ||||
| static const EnumPropertyItem prop_select_grouped_types[] = { | static const EnumPropertyItem prop_select_grouped_types[] = { | ||||
| {GP_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"}, | {GP_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"}, | ||||
| Show All 18 Lines | void GPENCIL_OT_select_grouped(wmOperatorType *ot) | ||||
| ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, GP_SEL_SAME_LAYER, "Type", ""); | ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, GP_SEL_SAME_LAYER, "Type", ""); | ||||
| } | } | ||||
| /* ********************************************** */ | /* ********************************************** */ | ||||
| /* Select First */ | /* Select First */ | ||||
| static int gpencil_select_first_exec(bContext *C, wmOperator *op) | static int gpencil_select_first_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| /* if not edit/sculpt mode, the event is catched but not processed */ | |||||
| if (GPENCIL_NONE_EDIT_MODE(gpd)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes"); | const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes"); | ||||
| const bool extend = RNA_boolean_get(op->ptr, "extend"); | const bool extend = RNA_boolean_get(op->ptr, "extend"); | ||||
| CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | ||||
| { | { | ||||
| /* skip stroke if we're only manipulating selected strokes */ | /* skip stroke if we're only manipulating selected strokes */ | ||||
| if (only_selected && !(gps->flag & GP_STROKE_SELECT)) { | if (only_selected && !(gps->flag & GP_STROKE_SELECT)) { | ||||
| continue; | continue; | ||||
| Show All 14 Lines | if ((extend == false) && (gps->totpoints > 1)) { | ||||
| for (; i < gps->totpoints; i++, pt++) { | for (; i < gps->totpoints; i++, pt++) { | ||||
| pt->flag &= ~GP_SPOINT_SELECT; | pt->flag &= ~GP_SPOINT_SELECT; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| /* updates */ | /* updates */ | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_select_first(wmOperatorType *ot) | void GPENCIL_OT_select_first(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Select First"; | ot->name = "Select First"; | ||||
| Show All 14 Lines | void GPENCIL_OT_select_first(wmOperatorType *ot) | ||||
| RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points"); | RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points"); | ||||
| } | } | ||||
| /* ********************************************** */ | /* ********************************************** */ | ||||
| /* Select First */ | /* Select First */ | ||||
| static int gpencil_select_last_exec(bContext *C, wmOperator *op) | static int gpencil_select_last_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| /* if not edit/sculpt mode, the event is catched but not processed */ | |||||
| if (GPENCIL_NONE_EDIT_MODE(gpd)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes"); | const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes"); | ||||
| const bool extend = RNA_boolean_get(op->ptr, "extend"); | const bool extend = RNA_boolean_get(op->ptr, "extend"); | ||||
| CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | ||||
| { | { | ||||
| /* skip stroke if we're only manipulating selected strokes */ | /* skip stroke if we're only manipulating selected strokes */ | ||||
| if (only_selected && !(gps->flag & GP_STROKE_SELECT)) { | if (only_selected && !(gps->flag & GP_STROKE_SELECT)) { | ||||
| continue; | continue; | ||||
| Show All 14 Lines | if ((extend == false) && (gps->totpoints > 1)) { | ||||
| for (; i < gps->totpoints - 1; i++, pt++) { | for (; i < gps->totpoints - 1; i++, pt++) { | ||||
| pt->flag &= ~GP_SPOINT_SELECT; | pt->flag &= ~GP_SPOINT_SELECT; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| /* updates */ | /* updates */ | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_select_last(wmOperatorType *ot) | void GPENCIL_OT_select_last(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Select Last"; | ot->name = "Select Last"; | ||||
| Show All 14 Lines | void GPENCIL_OT_select_last(wmOperatorType *ot) | ||||
| RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points"); | RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points"); | ||||
| } | } | ||||
| /* ********************************************** */ | /* ********************************************** */ | ||||
| /* Select More */ | /* Select More */ | ||||
| static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op)) | static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| /* if not edit/sculpt mode, the event is catched but not processed */ | |||||
| if (GPENCIL_NONE_EDIT_MODE(gpd)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | ||||
| { | { | ||||
| if (gps->flag & GP_STROKE_SELECT) { | if (gps->flag & GP_STROKE_SELECT) { | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| int i; | int i; | ||||
| bool prev_sel; | bool prev_sel; | ||||
| /* First Pass: Go in forward order, expanding selection if previous was selected (pre changes)... | /* First Pass: Go in forward order, expanding selection if previous was selected (pre changes)... | ||||
| Show All 30 Lines | if (gps->flag & GP_STROKE_SELECT) { | ||||
| prev_sel = false; | prev_sel = false; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| /* updates */ | /* updates */ | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_select_more(wmOperatorType *ot) | void GPENCIL_OT_select_more(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Select More"; | ot->name = "Select More"; | ||||
| ot->idname = "GPENCIL_OT_select_more"; | ot->idname = "GPENCIL_OT_select_more"; | ||||
| ot->description = "Grow sets of selected Grease Pencil points"; | ot->description = "Grow sets of selected Grease Pencil points"; | ||||
| /* callbacks */ | /* callbacks */ | ||||
| ot->exec = gpencil_select_more_exec; | ot->exec = gpencil_select_more_exec; | ||||
| ot->poll = gpencil_select_poll; | ot->poll = gpencil_select_poll; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| } | } | ||||
| /* ********************************************** */ | /* ********************************************** */ | ||||
| /* Select Less */ | /* Select Less */ | ||||
| static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op)) | static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| /* if not edit/sculpt mode, the event is catched but not processed */ | |||||
| if (GPENCIL_NONE_EDIT_MODE(gpd)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) | ||||
| { | { | ||||
| if (gps->flag & GP_STROKE_SELECT) { | if (gps->flag & GP_STROKE_SELECT) { | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| int i; | int i; | ||||
| bool prev_sel; | bool prev_sel; | ||||
| /* First Pass: Go in forward order, shrinking selection if previous was not selected (pre changes)... | /* First Pass: Go in forward order, shrinking selection if previous was not selected (pre changes)... | ||||
| Show All 31 Lines | if (gps->flag & GP_STROKE_SELECT) { | ||||
| prev_sel = false; | prev_sel = false; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| /* updates */ | /* updates */ | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_select_less(wmOperatorType *ot) | void GPENCIL_OT_select_less(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Select Less"; | ot->name = "Select Less"; | ||||
| Show All 13 Lines | |||||
| /* Helper to check if a given stroke is within the area */ | /* Helper to check if a given stroke is within the area */ | ||||
| /* NOTE: Code here is adapted (i.e. copied directly) from gpencil_paint.c::gp_stroke_eraser_dostroke() | /* NOTE: Code here is adapted (i.e. copied directly) from gpencil_paint.c::gp_stroke_eraser_dostroke() | ||||
| * It would be great to de-duplicate the logic here sometime, but that can wait... | * It would be great to de-duplicate the logic here sometime, but that can wait... | ||||
| */ | */ | ||||
| static bool gp_stroke_do_circle_sel( | static bool gp_stroke_do_circle_sel( | ||||
| bGPDstroke *gps, GP_SpaceConversion *gsc, | bGPDstroke *gps, GP_SpaceConversion *gsc, | ||||
| const int mx, const int my, const int radius, | const int mx, const int my, const int radius, | ||||
| const bool select, rcti *rect, const bool parented, float diff_mat[4][4]) | const bool select, rcti *rect, float diff_mat[4][4]) | ||||
| { | { | ||||
| bGPDspoint *pt1, *pt2; | bGPDspoint *pt1, *pt2; | ||||
| int x0 = 0, y0 = 0, x1 = 0, y1 = 0; | int x0 = 0, y0 = 0, x1 = 0, y1 = 0; | ||||
| int i; | int i; | ||||
| bool changed = false; | bool changed = false; | ||||
| if (gps->totpoints == 1) { | if (gps->totpoints == 1) { | ||||
| if (!parented) { | |||||
| gp_point_to_xy(gsc, gps, gps->points, &x0, &y0); | |||||
| } | |||||
| else { | |||||
| bGPDspoint pt_temp; | bGPDspoint pt_temp; | ||||
| gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); | gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); | ||||
| gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0); | gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0); | ||||
| } | |||||
| /* do boundbox check first */ | /* do boundbox check first */ | ||||
| if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) { | if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) { | ||||
| /* only check if point is inside */ | /* only check if point is inside */ | ||||
| if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) { | if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) { | ||||
| /* change selection */ | /* change selection */ | ||||
| if (select) { | if (select) { | ||||
| gps->points->flag |= GP_SPOINT_SELECT; | gps->points->flag |= GP_SPOINT_SELECT; | ||||
| Show All 11 Lines | static bool gp_stroke_do_circle_sel( | ||||
| else { | else { | ||||
| /* Loop over the points in the stroke, checking for intersections | /* Loop over the points in the stroke, checking for intersections | ||||
| * - an intersection means that we touched the stroke | * - an intersection means that we touched the stroke | ||||
| */ | */ | ||||
| for (i = 0; (i + 1) < gps->totpoints; i++) { | for (i = 0; (i + 1) < gps->totpoints; i++) { | ||||
| /* get points to work with */ | /* get points to work with */ | ||||
| pt1 = gps->points + i; | pt1 = gps->points + i; | ||||
| pt2 = gps->points + i + 1; | pt2 = gps->points + i + 1; | ||||
| if (!parented) { | |||||
| gp_point_to_xy(gsc, gps, pt1, &x0, &y0); | |||||
| gp_point_to_xy(gsc, gps, pt2, &x1, &y1); | |||||
| } | |||||
| else { | |||||
| bGPDspoint npt; | bGPDspoint npt; | ||||
| gp_point_to_parent_space(pt1, diff_mat, &npt); | gp_point_to_parent_space(pt1, diff_mat, &npt); | ||||
| gp_point_to_xy(gsc, gps, &npt, &x0, &y0); | gp_point_to_xy(gsc, gps, &npt, &x0, &y0); | ||||
| gp_point_to_parent_space(pt2, diff_mat, &npt); | gp_point_to_parent_space(pt2, diff_mat, &npt); | ||||
| gp_point_to_xy(gsc, gps, &npt, &x1, &y1); | gp_point_to_xy(gsc, gps, &npt, &x1, &y1); | ||||
| } | |||||
| /* check that point segment of the boundbox of the selection stroke */ | /* check that point segment of the boundbox of the selection stroke */ | ||||
| if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) || | if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) || | ||||
| ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1))) | ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1))) | ||||
| { | { | ||||
| int mval[2] = {mx, my}; | int mval[2] = {mx, my}; | ||||
| int mvalo[2] = {mx, my}; /* dummy - this isn't used... */ | int mvalo[2] = {mx, my}; /* dummy - this isn't used... */ | ||||
| Show All 27 Lines | static bool gp_stroke_do_circle_sel( | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| static int gpencil_circle_select_exec(bContext *C, wmOperator *op) | static int gpencil_circle_select_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| /* if not edit/sculpt mode, the event is catched but not processed */ | |||||
| if (GPENCIL_NONE_EDIT_MODE(gpd)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| ScrArea *sa = CTX_wm_area(C); | ScrArea *sa = CTX_wm_area(C); | ||||
| const int mx = RNA_int_get(op->ptr, "x"); | const int mx = RNA_int_get(op->ptr, "x"); | ||||
| const int my = RNA_int_get(op->ptr, "y"); | const int my = RNA_int_get(op->ptr, "y"); | ||||
| const int radius = RNA_int_get(op->ptr, "radius"); | const int radius = RNA_int_get(op->ptr, "radius"); | ||||
| bool select = !RNA_boolean_get(op->ptr, "deselect"); | bool select = !RNA_boolean_get(op->ptr, "deselect"); | ||||
| Show All 19 Lines | static int gpencil_circle_select_exec(bContext *C, wmOperator *op) | ||||
| rect.xmax = mx + radius; | rect.xmax = mx + radius; | ||||
| rect.ymax = my + radius; | rect.ymax = my + radius; | ||||
| /* find visible strokes, and select if hit */ | /* find visible strokes, and select if hit */ | ||||
| GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) | GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) | ||||
| { | { | ||||
| changed |= gp_stroke_do_circle_sel( | changed |= gp_stroke_do_circle_sel( | ||||
| gps, &gsc, mx, my, radius, select, &rect, | gps, &gsc, mx, my, radius, select, &rect, diff_mat); | ||||
| (gpl->parent != NULL), diff_mat); | |||||
| } | } | ||||
| GP_EDITABLE_STROKES_END; | GP_EDITABLE_STROKES_END; | ||||
| /* updates */ | /* updates */ | ||||
| if (changed) { | if (changed) { | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | ||||
| } | } | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_select_circle(wmOperatorType *ot) | void GPENCIL_OT_select_circle(wmOperatorType *ot) | ||||
| { | { | ||||
| Show All 16 Lines | void GPENCIL_OT_select_circle(wmOperatorType *ot) | ||||
| WM_operator_properties_gesture_circle_select(ot); | WM_operator_properties_gesture_circle_select(ot); | ||||
| } | } | ||||
| /* ********************************************** */ | /* ********************************************** */ | ||||
| /* Box Selection */ | /* Box Selection */ | ||||
| static int gpencil_border_select_exec(bContext *C, wmOperator *op) | static int gpencil_border_select_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| ScrArea *sa = CTX_wm_area(C); | ScrArea *sa = CTX_wm_area(C); | ||||
| const bool select = !RNA_boolean_get(op->ptr, "deselect"); | const bool select = !RNA_boolean_get(op->ptr, "deselect"); | ||||
| const bool extend = RNA_boolean_get(op->ptr, "extend"); | const bool extend = RNA_boolean_get(op->ptr, "extend") && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0); | ||||
| GP_SpaceConversion gsc = {NULL}; | GP_SpaceConversion gsc = {NULL}; | ||||
| rcti rect = {0}; | rcti rect = {0}; | ||||
| bool changed = false; | bool changed = false; | ||||
| /* sanity checks */ | /* sanity checks */ | ||||
| Show All 31 Lines | GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| int i; | int i; | ||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | ||||
| int x0, y0; | int x0, y0; | ||||
| /* convert point coords to screenspace */ | /* convert point coords to screenspace */ | ||||
| if (gpl->parent == NULL) { | |||||
| gp_point_to_xy(&gsc, gps, pt, &x0, &y0); | |||||
| } | |||||
| else { | |||||
| bGPDspoint pt2; | bGPDspoint pt2; | ||||
| gp_point_to_parent_space(pt, diff_mat, &pt2); | gp_point_to_parent_space(pt, diff_mat, &pt2); | ||||
| gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0); | gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0); | ||||
| } | |||||
| /* test if in selection rect */ | /* test if in selection rect */ | ||||
| if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0)) { | if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0)) { | ||||
| if (select) { | if (select) { | ||||
| pt->flag |= GP_SPOINT_SELECT; | pt->flag |= GP_SPOINT_SELECT; | ||||
| } | } | ||||
| else { | else { | ||||
| pt->flag &= ~GP_SPOINT_SELECT; | pt->flag &= ~GP_SPOINT_SELECT; | ||||
| } | } | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| /* Ensure that stroke selection is in sync with its points */ | /* Ensure that stroke selection is in sync with its points */ | ||||
| BKE_gpencil_stroke_sync_selection(gps); | BKE_gpencil_stroke_sync_selection(gps); | ||||
| } | } | ||||
| GP_EDITABLE_STROKES_END; | GP_EDITABLE_STROKES_END; | ||||
| /* if paint mode,delete selected points */ | |||||
| if (gpd->flag & GP_DATA_STROKE_PAINTMODE) { | |||||
| gp_delete_selected_point_wrap(C); | |||||
| changed = true; | |||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); | |||||
| } | |||||
| /* updates */ | /* updates */ | ||||
| if (changed) { | if (changed) { | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | ||||
| } | } | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_select_border(wmOperatorType *ot) | void GPENCIL_OT_select_border(wmOperatorType *ot) | ||||
| { | { | ||||
| Show All 17 Lines | void GPENCIL_OT_select_border(wmOperatorType *ot) | ||||
| WM_operator_properties_gesture_border_select(ot); | WM_operator_properties_gesture_border_select(ot); | ||||
| } | } | ||||
| /* ********************************************** */ | /* ********************************************** */ | ||||
| /* Lasso */ | /* Lasso */ | ||||
| static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) | static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| GP_SpaceConversion gsc = {NULL}; | GP_SpaceConversion gsc = {NULL}; | ||||
| rcti rect = {0}; | rcti rect = {0}; | ||||
| const bool extend = RNA_boolean_get(op->ptr, "extend"); | const bool extend = RNA_boolean_get(op->ptr, "extend") && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0); | ||||
| const bool select = !RNA_boolean_get(op->ptr, "deselect"); | const bool select = !RNA_boolean_get(op->ptr, "deselect"); | ||||
| int mcords_tot; | int mcords_tot; | ||||
| const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); | const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); | ||||
| bool changed = false; | bool changed = false; | ||||
| /* sanity check */ | /* sanity check */ | ||||
| Show All 27 Lines | static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| int i; | int i; | ||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | ||||
| int x0, y0; | int x0, y0; | ||||
| /* convert point coords to screenspace */ | /* convert point coords to screenspace */ | ||||
| if (gpl->parent == NULL) { | |||||
| gp_point_to_xy(&gsc, gps, pt, &x0, &y0); | |||||
| } | |||||
| else { | |||||
| bGPDspoint pt2; | bGPDspoint pt2; | ||||
| gp_point_to_parent_space(pt, diff_mat, &pt2); | gp_point_to_parent_space(pt, diff_mat, &pt2); | ||||
| gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0); | gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0); | ||||
| } | |||||
| /* test if in lasso boundbox + within the lasso noose */ | /* test if in lasso boundbox + within the lasso noose */ | ||||
| if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0) && | if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0) && | ||||
| BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX)) | BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX)) | ||||
| { | { | ||||
| if (select) { | if (select) { | ||||
| pt->flag |= GP_SPOINT_SELECT; | pt->flag |= GP_SPOINT_SELECT; | ||||
| } | } | ||||
| else { | else { | ||||
| pt->flag &= ~GP_SPOINT_SELECT; | pt->flag &= ~GP_SPOINT_SELECT; | ||||
| } | } | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| /* Ensure that stroke selection is in sync with its points */ | /* Ensure that stroke selection is in sync with its points */ | ||||
| BKE_gpencil_stroke_sync_selection(gps); | BKE_gpencil_stroke_sync_selection(gps); | ||||
| } | } | ||||
| GP_EDITABLE_STROKES_END; | GP_EDITABLE_STROKES_END; | ||||
| /* cleanup */ | /* cleanup */ | ||||
| MEM_freeN((void *)mcords); | MEM_freeN((void *)mcords); | ||||
| /* if paint mode,delete selected points */ | |||||
| if (gpd->flag & GP_DATA_STROKE_PAINTMODE) { | |||||
| gp_delete_selected_point_wrap(C); | |||||
| changed = true; | |||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); | |||||
| } | |||||
| /* updates */ | /* updates */ | ||||
| if (changed) { | if (changed) { | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | ||||
| } | } | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_select_lasso(wmOperatorType *ot) | void GPENCIL_OT_select_lasso(wmOperatorType *ot) | ||||
| { | { | ||||
| Show All 15 Lines | |||||
| } | } | ||||
| /* ********************************************** */ | /* ********************************************** */ | ||||
| /* Mouse Click to Select */ | /* Mouse Click to Select */ | ||||
| static int gpencil_select_exec(bContext *C, wmOperator *op) | static int gpencil_select_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| ScrArea *sa = CTX_wm_area(C); | ScrArea *sa = CTX_wm_area(C); | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| /* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */ | /* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */ | ||||
| const float radius = 0.75f * U.widget_unit; | const float radius = 0.75f * U.widget_unit; | ||||
| const int radius_squared = (int)(radius * radius); | const int radius_squared = (int)(radius * radius); | ||||
| bool extend = RNA_boolean_get(op->ptr, "extend"); | bool extend = RNA_boolean_get(op->ptr, "extend"); | ||||
| bool deselect = RNA_boolean_get(op->ptr, "deselect"); | bool deselect = RNA_boolean_get(op->ptr, "deselect"); | ||||
| bool toggle = RNA_boolean_get(op->ptr, "toggle"); | bool toggle = RNA_boolean_get(op->ptr, "toggle"); | ||||
| Show All 25 Lines | static int gpencil_select_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| int i; | int i; | ||||
| /* firstly, check for hit-point */ | /* firstly, check for hit-point */ | ||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | ||||
| int xy[2]; | int xy[2]; | ||||
| if (gpl->parent == NULL) { | |||||
| gp_point_to_xy(&gsc, gps, pt, &xy[0], &xy[1]); | |||||
| } | |||||
| else { | |||||
| bGPDspoint pt2; | bGPDspoint pt2; | ||||
| gp_point_to_parent_space(pt, diff_mat, &pt2); | gp_point_to_parent_space(pt, diff_mat, &pt2); | ||||
| gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]); | gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]); | ||||
| } | |||||
| /* do boundbox check first */ | /* do boundbox check first */ | ||||
| if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) { | if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) { | ||||
| const int pt_distance = len_manhattan_v2v2_int(mval, xy); | const int pt_distance = len_manhattan_v2v2_int(mval, xy); | ||||
| /* check if point is inside */ | /* check if point is inside */ | ||||
| if (pt_distance <= radius_squared) { | if (pt_distance <= radius_squared) { | ||||
| /* only use this point if it is a better match than the current hit - T44685 */ | /* only use this point if it is a better match than the current hit - T44685 */ | ||||
| ▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | else { | ||||
| /* ensure that stroke is selected correctly */ | /* ensure that stroke is selected correctly */ | ||||
| BKE_gpencil_stroke_sync_selection(hit_stroke); | BKE_gpencil_stroke_sync_selection(hit_stroke); | ||||
| } | } | ||||
| } | } | ||||
| /* updates */ | /* updates */ | ||||
| if (hit_point != NULL) { | if (hit_point != NULL) { | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); | |||||
| /* copy on write tag is needed, or else no refresh happens */ | |||||
| DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); | ||||
| } | } | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int gpencil_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int gpencil_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| Show All 32 Lines | |||||