forked from blender/blender
me-main #1
@ -5628,6 +5628,7 @@ def km_curves(params):
|
|||||||
("curves.disable_selection", {"type": 'ONE', "value": 'PRESS', "alt": True}, None),
|
("curves.disable_selection", {"type": 'ONE', "value": 'PRESS', "alt": True}, None),
|
||||||
("curves.disable_selection", {"type": 'TWO', "value": 'PRESS', "alt": True}, None),
|
("curves.disable_selection", {"type": 'TWO', "value": 'PRESS', "alt": True}, None),
|
||||||
*_template_items_select_actions(params, "curves.select_all"),
|
*_template_items_select_actions(params, "curves.select_all"),
|
||||||
|
("curves.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||||
])
|
])
|
||||||
|
|
||||||
return keymap
|
return keymap
|
||||||
|
@ -2052,6 +2052,7 @@ class VIEW3D_MT_select_edit_curves(Menu):
|
|||||||
layout.operator("curves.select_all", text="Invert").action = 'INVERT'
|
layout.operator("curves.select_all", text="Invert").action = 'INVERT'
|
||||||
layout.operator("curves.select_random", text="Random")
|
layout.operator("curves.select_random", text="Random")
|
||||||
layout.operator("curves.select_end", text="Endpoints")
|
layout.operator("curves.select_end", text="Endpoints")
|
||||||
|
layout.operator("curves.select_linked", text="Linked")
|
||||||
|
|
||||||
|
|
||||||
class VIEW3D_MT_select_sculpt_curves(Menu):
|
class VIEW3D_MT_select_sculpt_curves(Menu):
|
||||||
|
@ -157,6 +157,19 @@ bool curves_poll(bContext *C)
|
|||||||
return curves_poll_impl(C, false, false, false);
|
return curves_poll_impl(C, false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool editable_curves_point_domain_poll(bContext *C)
|
||||||
|
{
|
||||||
|
if (!curves::editable_curves_poll(C)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const Curves *curves_id = static_cast<const Curves *>(CTX_data_active_object(C)->data);
|
||||||
|
if (curves_id->selection_domain != ATTR_DOMAIN_POINT) {
|
||||||
|
CTX_wm_operator_poll_msg_set(C, "Only available in point selection mode");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
using bke::CurvesGeometry;
|
using bke::CurvesGeometry;
|
||||||
|
|
||||||
namespace convert_to_particle_system {
|
namespace convert_to_particle_system {
|
||||||
@ -931,19 +944,6 @@ static void CURVES_OT_select_random(wmOperatorType *ot)
|
|||||||
1.0f);
|
1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool select_end_poll(bContext *C)
|
|
||||||
{
|
|
||||||
if (!curves::editable_curves_poll(C)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const Curves *curves_id = static_cast<const Curves *>(CTX_data_active_object(C)->data);
|
|
||||||
if (curves_id->selection_domain != ATTR_DOMAIN_POINT) {
|
|
||||||
CTX_wm_operator_poll_msg_set(C, "Only available in point selection mode");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int select_end_exec(bContext *C, wmOperator *op)
|
static int select_end_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
VectorSet<Curves *> unique_curves = curves::get_unique_editable_curves(*C);
|
VectorSet<Curves *> unique_curves = curves::get_unique_editable_curves(*C);
|
||||||
@ -952,7 +952,7 @@ static int select_end_exec(bContext *C, wmOperator *op)
|
|||||||
|
|
||||||
for (Curves *curves_id : unique_curves) {
|
for (Curves *curves_id : unique_curves) {
|
||||||
CurvesGeometry &curves = curves_id->geometry.wrap();
|
CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||||
select_ends(curves, eAttrDomain(curves_id->selection_domain), amount, end_points);
|
select_ends(curves, amount, end_points);
|
||||||
|
|
||||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
|
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
|
||||||
* attribute for now. */
|
* attribute for now. */
|
||||||
@ -970,7 +970,7 @@ static void CURVES_OT_select_end(wmOperatorType *ot)
|
|||||||
ot->description = "Select end points of curves";
|
ot->description = "Select end points of curves";
|
||||||
|
|
||||||
ot->exec = select_end_exec;
|
ot->exec = select_end_exec;
|
||||||
ot->poll = select_end_poll;
|
ot->poll = editable_curves_point_domain_poll;
|
||||||
|
|
||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
|
||||||
@ -983,6 +983,33 @@ static void CURVES_OT_select_end(wmOperatorType *ot)
|
|||||||
ot->srna, "amount", 1, 0, INT32_MAX, "Amount", "Number of points to select", 0, INT32_MAX);
|
ot->srna, "amount", 1, 0, INT32_MAX, "Amount", "Number of points to select", 0, INT32_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int select_linked_exec(bContext *C, wmOperator * /*op*/)
|
||||||
|
{
|
||||||
|
VectorSet<Curves *> unique_curves = get_unique_editable_curves(*C);
|
||||||
|
for (Curves *curves_id : unique_curves) {
|
||||||
|
CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||||
|
select_linked(curves);
|
||||||
|
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
|
||||||
|
* attribute for now. */
|
||||||
|
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
|
||||||
|
WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CURVES_OT_select_linked(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
ot->name = "Select Linked";
|
||||||
|
ot->idname = __func__;
|
||||||
|
ot->description = "Select all points in curves with any point selection";
|
||||||
|
|
||||||
|
ot->exec = select_linked_exec;
|
||||||
|
ot->poll = editable_curves_point_domain_poll;
|
||||||
|
|
||||||
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
}
|
||||||
|
|
||||||
namespace surface_set {
|
namespace surface_set {
|
||||||
|
|
||||||
static bool surface_set_poll(bContext *C)
|
static bool surface_set_poll(bContext *C)
|
||||||
@ -1078,6 +1105,7 @@ void ED_operatortypes_curves()
|
|||||||
WM_operatortype_append(CURVES_OT_select_all);
|
WM_operatortype_append(CURVES_OT_select_all);
|
||||||
WM_operatortype_append(CURVES_OT_select_random);
|
WM_operatortype_append(CURVES_OT_select_random);
|
||||||
WM_operatortype_append(CURVES_OT_select_end);
|
WM_operatortype_append(CURVES_OT_select_end);
|
||||||
|
WM_operatortype_append(CURVES_OT_select_linked);
|
||||||
WM_operatortype_append(CURVES_OT_surface_set);
|
WM_operatortype_append(CURVES_OT_surface_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +164,21 @@ bool has_anything_selected(const bke::CurvesGeometry &curves)
|
|||||||
return !selection || contains(selection, true);
|
return !selection || contains(selection, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_anything_selected(const GSpan selection)
|
||||||
|
{
|
||||||
|
if (selection.type().is<bool>()) {
|
||||||
|
return selection.typed<bool>().contains(true);
|
||||||
|
}
|
||||||
|
else if (selection.type().is<float>()) {
|
||||||
|
for (const float elem : selection.typed<float>()) {
|
||||||
|
if (elem > 0.0f) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void invert_selection(MutableSpan<float> selection)
|
static void invert_selection(MutableSpan<float> selection)
|
||||||
{
|
{
|
||||||
threading::parallel_for(selection.index_range(), 2048, [&](IndexRange range) {
|
threading::parallel_for(selection.index_range(), 2048, [&](IndexRange range) {
|
||||||
@ -203,14 +218,12 @@ void select_all(bke::CurvesGeometry &curves, const eAttrDomain selection_domain,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void select_ends(bke::CurvesGeometry &curves,
|
void select_ends(bke::CurvesGeometry &curves, int amount, bool end_points)
|
||||||
const eAttrDomain selection_domain,
|
|
||||||
int amount,
|
|
||||||
bool end_points)
|
|
||||||
{
|
{
|
||||||
const bool was_anything_selected = has_anything_selected(curves);
|
const bool was_anything_selected = has_anything_selected(curves);
|
||||||
|
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||||
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
|
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
|
||||||
curves, selection_domain, CD_PROP_BOOL);
|
curves, ATTR_DOMAIN_POINT, CD_PROP_BOOL);
|
||||||
if (!was_anything_selected) {
|
if (!was_anything_selected) {
|
||||||
fill_selection_true(selection.span);
|
fill_selection_true(selection.span);
|
||||||
}
|
}
|
||||||
@ -223,7 +236,6 @@ void select_ends(bke::CurvesGeometry &curves,
|
|||||||
MutableSpan<T> selection_typed = selection.span.typed<T>();
|
MutableSpan<T> selection_typed = selection.span.typed<T>();
|
||||||
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
|
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
|
||||||
for (const int curve_i : range) {
|
for (const int curve_i : range) {
|
||||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
|
||||||
if (end_points) {
|
if (end_points) {
|
||||||
selection_typed.slice(points_by_curve[curve_i].drop_back(amount)).fill(T(0));
|
selection_typed.slice(points_by_curve[curve_i].drop_back(amount)).fill(T(0));
|
||||||
}
|
}
|
||||||
@ -237,6 +249,23 @@ void select_ends(bke::CurvesGeometry &curves,
|
|||||||
selection.finish();
|
selection.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void select_linked(bke::CurvesGeometry &curves)
|
||||||
|
{
|
||||||
|
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||||
|
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
|
||||||
|
curves, ATTR_DOMAIN_POINT, CD_PROP_BOOL);
|
||||||
|
|
||||||
|
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
|
||||||
|
for (const int curve_i : range) {
|
||||||
|
GMutableSpan selection_curve = selection.span.slice(points_by_curve[curve_i]);
|
||||||
|
if (has_anything_selected(selection_curve)) {
|
||||||
|
fill_selection_true(selection_curve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
selection.finish();
|
||||||
|
}
|
||||||
|
|
||||||
void select_random(bke::CurvesGeometry &curves,
|
void select_random(bke::CurvesGeometry &curves,
|
||||||
const eAttrDomain selection_domain,
|
const eAttrDomain selection_domain,
|
||||||
uint32_t random_seed,
|
uint32_t random_seed,
|
||||||
|
@ -89,6 +89,11 @@ void fill_selection_true(GMutableSpan span);
|
|||||||
*/
|
*/
|
||||||
bool has_anything_selected(const bke::CurvesGeometry &curves);
|
bool has_anything_selected(const bke::CurvesGeometry &curves);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if any element in the span is selected, on either domain with either type.
|
||||||
|
*/
|
||||||
|
bool has_anything_selected(GSpan selection);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find curves that have any point selected (a selection factor greater than zero),
|
* Find curves that have any point selected (a selection factor greater than zero),
|
||||||
* or curves that have their own selection factor greater than zero.
|
* or curves that have their own selection factor greater than zero.
|
||||||
@ -123,10 +128,12 @@ void select_all(bke::CurvesGeometry &curves, const eAttrDomain selection_domain,
|
|||||||
* \param amount: The amount of points to select from the front or back.
|
* \param amount: The amount of points to select from the front or back.
|
||||||
* \param end_points: If true, select the last point(s), if false, select the first point(s).
|
* \param end_points: If true, select the last point(s), if false, select the first point(s).
|
||||||
*/
|
*/
|
||||||
void select_ends(bke::CurvesGeometry &curves,
|
void select_ends(bke::CurvesGeometry &curves, int amount, bool end_points);
|
||||||
const eAttrDomain selection_domain,
|
|
||||||
int amount,
|
/**
|
||||||
bool end_points);
|
* Select the points of all curves that have at least one point selected.
|
||||||
|
*/
|
||||||
|
void select_linked(bke::CurvesGeometry &curves);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select random points or curves.
|
* Select random points or curves.
|
||||||
|
Loading…
Reference in New Issue
Block a user