Files
test2/source/blender/editors/curves/intern/select_linked_pick.cc
Hans Goudey 1f92fd7577 Refactor: Use AttrType instead of CustomData type in attribute API
Change `eCustomDataType` to `bke::AttrType` for uses of the attribute
API (the `AttributeAccessor` one anyway). I didn't touch any values that
might be saved in files; those should be handled on a case by case basis.

Part of #122398

Pull Request: https://projects.blender.org/blender/blender/pulls/141301
2025-07-01 22:14:26 +02:00

146 lines
5.1 KiB
C++

/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_context.hh"
#include "BKE_curves.hh"
#include "BKE_layer.hh"
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "DEG_depsgraph.hh"
#include "WM_api.hh"
#include "WM_types.hh"
#include "ED_curves.hh"
#include "ED_view3d.hh"
namespace blender::ed::curves {
struct ClosestCurveDataBlock {
Curves *curves_id = nullptr;
FindClosestData elem;
};
static ClosestCurveDataBlock find_closest_curve(const Depsgraph &depsgraph,
const ViewContext &vc,
const Span<Base *> bases,
const int2 &mval)
{
return threading::parallel_reduce(
bases.index_range(),
1L,
ClosestCurveDataBlock(),
[&](const IndexRange range, const ClosestCurveDataBlock &init) {
ClosestCurveDataBlock new_closest = init;
for (Base *base : bases.slice(range)) {
Object &curves_ob = *base->object;
Curves &curves_id = *static_cast<Curves *>(curves_ob.data);
bke::crazyspace::GeometryDeformation deformation =
bke::crazyspace::get_evaluated_curves_deformation(depsgraph, curves_ob);
const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
const float4x4 projection = ED_view3d_ob_project_mat_get(vc.rv3d, &curves_ob);
foreach_selectable_curve_range(
curves,
deformation,
eHandleDisplay(vc.v3d->overlay.handle_display),
[&](IndexRange range, Span<float3> positions, StringRef /*selection_name*/) {
std::optional<FindClosestData> new_closest_elem = closest_elem_find_screen_space(
vc,
curves.points_by_curve(),
positions,
curves.cyclic(),
projection,
range,
bke::AttrDomain::Curve,
mval,
new_closest.elem);
if (new_closest_elem) {
new_closest.elem = *new_closest_elem;
new_closest.curves_id = &curves_id;
}
});
}
return new_closest;
},
[](const ClosestCurveDataBlock &a, const ClosestCurveDataBlock &b) {
return (a.elem.distance_sq < b.elem.distance_sq) ? a : b;
});
}
static bool select_linked_pick(bContext &C, const int2 &mval, const SelectPick_Params &params)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(&C);
const ViewContext vc = ED_view3d_viewcontext_init(&C, depsgraph);
const Vector<Base *> bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.scene, vc.view_layer, vc.v3d);
const ClosestCurveDataBlock closest = find_closest_curve(*depsgraph, vc, bases, mval);
if (!closest.curves_id) {
return false;
}
bke::CurvesGeometry &closest_curves = closest.curves_id->geometry.wrap();
const bke::AttrDomain selection_domain = bke::AttrDomain(closest.curves_id->selection_domain);
if (selection_domain == bke::AttrDomain::Point) {
const OffsetIndices points_by_curve = closest_curves.points_by_curve();
foreach_selection_attribute_writer(
closest_curves, bke::AttrDomain::Point, [&](bke::GSpanAttributeWriter &selection) {
for (const int point : points_by_curve[closest.elem.index]) {
apply_selection_operation_at_index(selection.span, point, params.sel_op);
}
});
}
else if (selection_domain == bke::AttrDomain::Curve) {
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
closest_curves, bke::AttrDomain::Curve, bke::AttrType::Bool);
apply_selection_operation_at_index(selection.span, closest.elem.index, params.sel_op);
selection.finish();
}
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
* generic attribute for now. */
DEG_id_tag_update(&closest.curves_id->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, closest.curves_id);
return true;
}
static wmOperatorStatus select_linked_pick_invoke(bContext *C,
wmOperator *op,
const wmEvent *event)
{
SelectPick_Params params{};
params.sel_op = RNA_boolean_get(op->ptr, "deselect") ? SEL_OP_SUB : SEL_OP_ADD;
params.deselect_all = false;
params.select_passthrough = false;
if (!select_linked_pick(*C, event->mval, params)) {
return OPERATOR_CANCELLED;
}
return OPERATOR_FINISHED;
}
void CURVES_OT_select_linked_pick(wmOperatorType *ot)
{
ot->name = "Select Linked";
ot->idname = "CURVES_OT_select_linked_pick";
ot->description = "Select all points in the curve under the cursor";
ot->invoke = select_linked_pick_invoke;
ot->poll = editable_curves_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna,
"deselect",
false,
"Deselect",
"Deselect linked control points rather than selecting them");
}
} // namespace blender::ed::curves