Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c4
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c19
-rw-r--r--source/blender/editors/animation/anim_ops.c82
-rw-r--r--source/blender/editors/animation/drivers.c2
-rw-r--r--source/blender/editors/animation/keyframing.c58
-rw-r--r--source/blender/editors/animation/time_scrub_ui.c2
-rw-r--r--source/blender/editors/armature/editarmature_undo.c2
-rw-r--r--source/blender/editors/curve/editcurve_undo.c2
-rw-r--r--source/blender/editors/curve/editfont_undo.c2
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c2
-rw-r--r--source/blender/editors/include/ED_keyframing.h2
-rw-r--r--source/blender/editors/include/ED_mesh.h2
-rw-r--r--source/blender/editors/include/UI_interface.h55
-rw-r--r--source/blender/editors/interface/interface.c3
-rw-r--r--source/blender/editors/interface/interface_context_menu.c2
-rw-r--r--source/blender/editors/interface/interface_draw.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c300
-rw-r--r--source/blender/editors/interface/interface_icons.c2
-rw-r--r--source/blender/editors/interface/interface_intern.h3
-rw-r--r--source/blender/editors/interface/interface_layout.c2
-rw-r--r--source/blender/editors/interface/interface_templates.c14
-rw-r--r--source/blender/editors/interface/interface_utils.c2
-rw-r--r--source/blender/editors/interface/interface_widgets.c13
-rw-r--r--source/blender/editors/interface/view2d_ops.c2
-rw-r--r--source/blender/editors/io/io_alembic.c36
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c1
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c4
-rw-r--r--source/blender/editors/mesh/editmesh_path.c1
-rw-r--r--source/blender/editors/mesh/editmesh_select.c1
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c1
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c7
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c17
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c48
-rw-r--r--source/blender/editors/mesh/mesh_data.c1
-rw-r--r--source/blender/editors/metaball/editmball_undo.c2
-rw-r--r--source/blender/editors/object/object_add.c2
-rw-r--r--source/blender/editors/object/object_edit.c2
-rw-r--r--source/blender/editors/object/object_relations.c33
-rw-r--r--source/blender/editors/object/object_transform.c490
-rw-r--r--source/blender/editors/screen/area.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c2
-rw-r--r--source/blender/editors/space_action/action_data.c4
-rw-r--r--source/blender/editors/space_file/file_draw.c28
-rw-r--r--source/blender/editors/space_file/file_intern.h5
-rw-r--r--source/blender/editors/space_file/file_ops.c24
-rw-r--r--source/blender/editors/space_file/filelist.c35
-rw-r--r--source/blender/editors/space_file/filelist.h3
-rw-r--r--source/blender/editors/space_file/filesel.c53
-rw-r--r--source/blender/editors/space_file/space_file.c12
-rw-r--r--source/blender/editors/space_image/image_undo.c2
-rw-r--r--source/blender/editors/space_info/info_ops.c9
-rw-r--r--source/blender/editors/space_nla/nla_channels.c14
-rw-r--r--source/blender/editors/space_nla/nla_edit.c15
-rw-r--r--source/blender/editors/space_nla/nla_ops.c16
-rw-r--r--source/blender/editors/space_nla/nla_select.c4
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt18
-rw-r--r--source/blender/editors/space_node/node_buttons.c223
-rw-r--r--source/blender/editors/space_node/node_draw.cc66
-rw-r--r--source/blender/editors/space_node/node_edit.cc103
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc88
-rw-r--r--source/blender/editors/space_node/node_intern.h4
-rw-r--r--source/blender/editors/space_node/node_ops.c1
-rw-r--r--source/blender/editors/space_node/space_node.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library.cc34
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc91
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c6
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c6
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt5
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc23
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc6
-rw-r--r--source/blender/editors/space_text/text_undo.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c111
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_fly.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_walk.c85
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c70
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c2
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_edge.c1
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_uv.c1
-rw-r--r--source/blender/editors/transform/transform_convert_object.c4
-rw-r--r--source/blender/editors/transform/transform_snap_object.c6
-rw-r--r--source/blender/editors/uvedit/uvedit_islands.c1
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c6
92 files changed, 1485 insertions, 967 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index f69830fc015..87688ee343c 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -4025,7 +4025,7 @@ static bool acf_nlaaction_setting_valid(bAnimContext *UNUSED(ac),
/* conditionally supported */
case ACHANNEL_SETTING_PINNED: /* pinned - map/unmap */
if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
- /* this should only appear in tweakmode */
+ /* This should only appear in tweak-mode. */
return true;
}
else {
@@ -5176,7 +5176,7 @@ void ANIM_channel_draw_widgets(const bContext *C,
}
/* step 3) draw special toggles .................................
- * - in Graph Editor, checkboxes for visibility in curves area
+ * - in Graph Editor, check-boxes for visibility in curves area
* - in NLA Editor, glowing dots for solo/not solo...
* - in Grease Pencil mode, color swatches for layer color
*/
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 136cdefd2ec..8f8c1c067d4 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -747,7 +747,7 @@ static bool animedit_poll_channels_active(bContext *C)
return 1;
}
-/* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */
+/* Poll callback for Animation Editor channels list region + not in NLA-tweak-mode for NLA. */
static bool animedit_poll_channels_nla_tweakmode_off(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -763,7 +763,7 @@ static bool animedit_poll_channels_nla_tweakmode_off(bContext *C)
return 0;
}
- /* NLA TweakMode test */
+ /* NLA tweak-mode test. */
if (area->spacetype == SPACE_NLA) {
if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) {
return 0;
@@ -1283,6 +1283,9 @@ static void split_groups_action_temp(bAction *act, bActionGroup *tgrp)
else {
group_fcurves_last->next->prev = group_fcurves_first->prev;
}
+
+ /* Clear links pointing outside the per-group list. */
+ group_fcurves_first->prev = group_fcurves_last->next = NULL;
}
/* Initialize memory for temp-group */
@@ -1337,24 +1340,12 @@ static void join_groups_action_temp(bAction *act)
if (agrp->flag & AGRP_TEMP) {
LISTBASE_FOREACH (FCurve *, fcu, &agrp->channels) {
fcu->grp = NULL;
- if (fcu == agrp->channels.last) {
- break;
- }
}
BLI_remlink(&act->groups, agrp);
break;
}
}
-
- /* BLI_movelisttolist() doesn't touch first->prev and last->next pointers in its "dst" list.
- * Ensure that after the reshuffling the list is properly terminated. */
- if (!BLI_listbase_is_empty(&act->curves)) {
- FCurve *act_fcurves_first = act->curves.first;
- act_fcurves_first->prev = NULL;
- FCurve *act_fcurves_last = act->curves.last;
- act_fcurves_last->next = NULL;
- }
}
/* Change the order of anim-channels within action
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 73b9b118148..6f3277397c5 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -51,8 +51,10 @@
#include "DEG_depsgraph.h"
+#include "SEQ_iterator.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
+#include "SEQ_transform.h"
#include "anim_intern.h"
@@ -81,6 +83,49 @@ static bool change_frame_poll(bContext *C)
return false;
}
+static int seq_snap_threshold_get_frame_distance(bContext *C)
+{
+ const int snap_distance = SEQ_tool_settings_snap_distance_get(CTX_data_scene(C));
+ const ARegion *region = CTX_wm_region(C);
+ return round_fl_to_int(UI_view2d_region_to_view_x(&region->v2d, snap_distance) -
+ UI_view2d_region_to_view_x(&region->v2d, 0));
+}
+
+static void seq_frame_snap_update_best(const int position,
+ const int timeline_frame,
+ int *r_best_frame,
+ int *r_best_distance)
+{
+ if (abs(position - timeline_frame) < *r_best_distance) {
+ *r_best_distance = abs(position - timeline_frame);
+ *r_best_frame = position;
+ }
+}
+
+static int seq_frame_apply_snap(bContext *C, Scene *scene, const int timeline_frame)
+{
+
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene, false));
+ SeqCollection *strips = SEQ_query_all_strips(seqbase);
+
+ int best_frame = 0;
+ int best_distance = MAXFRAME;
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ seq_frame_snap_update_best(
+ SEQ_transform_get_left_handle_frame(seq), timeline_frame, &best_frame, &best_distance);
+ seq_frame_snap_update_best(
+ SEQ_transform_get_right_handle_frame(seq), timeline_frame, &best_frame, &best_distance);
+ }
+ SEQ_collection_free(strips);
+
+ if (best_distance < seq_snap_threshold_get_frame_distance(C)) {
+ return best_frame;
+ }
+
+ return timeline_frame;
+}
+
/* Set the new frame number */
static void change_frame_apply(bContext *C, wmOperator *op)
{
@@ -90,7 +135,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
if (do_snap) {
if (CTX_wm_space_seq(C)) {
- frame = SEQ_time_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false);
+ frame = seq_frame_apply_snap(C, scene, frame);
}
else {
frame = BKE_scene_frame_snap_by_seconds(scene, 1.0, frame);
@@ -181,6 +226,18 @@ static void change_frame_seq_preview_end(bContext *C)
}
}
+static bool use_sequencer_snapping(bContext *C)
+{
+ if (!CTX_wm_space_seq(C)) {
+ return false;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+ short snap_flag = SEQ_tool_settings_snap_flag_get(scene);
+ return (scene->toolsettings->snap_flag & SCE_SNAP_SEQ) &&
+ (snap_flag & SEQ_SNAP_CURRENT_FRAME_TO_STRIPS);
+}
+
/* Modal Operator init */
static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -190,6 +247,10 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
*/
RNA_float_set(op->ptr, "frame", frame_from_event(C, event));
+ if (use_sequencer_snapping(C)) {
+ RNA_boolean_set(op->ptr, "snap", true);
+ }
+
change_frame_seq_preview_begin(C, event);
change_frame_apply(C, op);
@@ -231,11 +292,22 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
case EVT_LEFTCTRLKEY:
case EVT_RIGHTCTRLKEY:
- if (event->val == KM_RELEASE) {
- RNA_boolean_set(op->ptr, "snap", false);
+ /* Use Ctrl key to invert snapping in sequencer. */
+ if (use_sequencer_snapping(C)) {
+ if (event->val == KM_RELEASE) {
+ RNA_boolean_set(op->ptr, "snap", true);
+ }
+ else if (event->val == KM_PRESS) {
+ RNA_boolean_set(op->ptr, "snap", false);
+ }
}
- else if (event->val == KM_PRESS) {
- RNA_boolean_set(op->ptr, "snap", true);
+ else {
+ if (event->val == KM_RELEASE) {
+ RNA_boolean_set(op->ptr, "snap", false);
+ }
+ else if (event->val == KM_PRESS) {
+ RNA_boolean_set(op->ptr, "snap", true);
+ }
}
break;
}
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 16eb2f6b6f2..bfaa76b3bf9 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -80,7 +80,7 @@ FCurve *verify_driver_fcurve(ID *id,
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if (adt == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
- adt = BKE_animdata_add_id(id);
+ adt = BKE_animdata_ensure_id(id);
}
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 3751555f18c..0a499232ba9 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -85,6 +85,8 @@ static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op,
PropertyRNA *prop,
Scene *scene);
+static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *ks);
+
/* ************************************************** */
/* Keyframing Setting Wrangling */
@@ -140,7 +142,7 @@ bAction *ED_id_action_ensure(Main *bmain, ID *id)
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if (adt == NULL) {
- adt = BKE_animdata_add_id(id);
+ adt = BKE_animdata_ensure_id(id);
}
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
@@ -2079,42 +2081,19 @@ void ANIM_OT_keyframe_insert_menu(wmOperatorType *ot)
static int delete_key_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
- int num_channels;
-
KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene);
if (ks == NULL) {
return OPERATOR_CANCELLED;
}
- const int prop_type = RNA_property_type(op->type->prop);
- if (prop_type == PROP_ENUM) {
- int type = RNA_property_enum_get(op->ptr, op->type->prop);
- ks = ANIM_keyingset_get_from_enum_type(scene, type);
- if (ks == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
- return OPERATOR_CANCELLED;
- }
- }
- else if (prop_type == PROP_STRING) {
- char type_id[MAX_ID_NAME - 2];
- RNA_property_string_get(op->ptr, op->type->prop, type_id);
- ks = ANIM_keyingset_get_from_idname(scene, type_id);
-
- if (ks == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Active Keying Set '%s' not found", type_id);
- return OPERATOR_CANCELLED;
- }
- }
- else {
- BLI_assert(0);
- }
+ return delete_key_using_keying_set(C, op, ks);
+}
- /* report failure */
- if (ks == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
- return OPERATOR_CANCELLED;
- }
+static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *ks)
+{
+ Scene *scene = CTX_data_scene(C);
+ float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
+ int num_channels;
/* try to delete keyframes for the channels specified by KeyingSet */
num_channels = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_DELETE, cfra);
@@ -2130,7 +2109,8 @@ static int delete_key_exec(bContext *C, wmOperator *op)
if (num_channels > 0) {
/* if the appropriate properties have been set, make a note that we've inserted something */
- if (RNA_boolean_get(op->ptr, "confirm_success")) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "confirm_success");
+ if (prop != NULL && RNA_property_boolean_get(op->ptr, prop)) {
BKE_reportf(op->reports,
RPT_INFO,
"Successfully removed %d keyframes for keying set '%s'",
@@ -2301,7 +2281,7 @@ void ANIM_OT_keyframe_clear_v3d(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int delete_key_v3d_exec(bContext *C, wmOperator *op)
+static int delete_key_v3d_without_keying_set(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
float cfra = (float)CFRA;
@@ -2408,6 +2388,18 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static int delete_key_v3d_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ KeyingSet *ks = ANIM_scene_get_active_keyingset(scene);
+
+ if (ks == NULL) {
+ return delete_key_v3d_without_keying_set(C, op);
+ }
+
+ return delete_key_using_keying_set(C, op, ks);
+}
+
void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c
index 034378399b9..6af033f3cf2 100644
--- a/source/blender/editors/animation/time_scrub_ui.c
+++ b/source/blender/editors/animation/time_scrub_ui.c
@@ -109,7 +109,7 @@ static void draw_current_frame(const Scene *scene,
if (draw_line) {
/* Draw vertical line to from the bottom of the current frame box to the bottom of the screen.
*/
- const float subframe_x = UI_view2d_view_to_region_x(v2d, BKE_scene_frame_get(scene));
+ const float subframe_x = UI_view2d_view_to_region_x(v2d, BKE_scene_ctime_get(scene));
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index 725945f8edc..832e75b2a8b 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -206,7 +206,7 @@ static void armature_undosys_step_decode(struct bContext *C,
}
undoarm_to_editarm(&elem->data, arm);
arm->needs_flush_to_id = 1;
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&arm->id, ID_RECALC_GEOMETRY);
}
/* The first element is always active */
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 88f6398567d..210411c6eb5 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -267,7 +267,7 @@ static void curve_undosys_step_decode(struct bContext *C,
}
undocurve_to_editcurve(bmain, &elem->data, obedit->data, &obedit->shapenr);
cu->editnurb->needs_flush_to_id = 1;
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&cu->id, ID_RECALC_GEOMETRY);
}
/* The first element is always active */
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index b61506d9346..6eaf8971eb0 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -379,7 +379,7 @@ static void font_undosys_step_decode(struct bContext *C,
Curve *cu = obedit->data;
undofont_to_editfont(&us->data, cu);
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&cu->id, ID_RECALC_GEOMETRY);
ED_undo_object_set_active_or_warn(
CTX_data_scene(C), CTX_data_view_layer(C), obedit, us_p->name, &LOG);
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 7bc4c307935..4b0c5ccd285 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -1172,7 +1172,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
* eraser region (either within stroke painted, or on its lines)
- * - this assumes that linewidth is irrelevant
+ * - this assumes that line-width is irrelevant.
*/
if (gpencil_stroke_inside_circle(mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
if ((annotation_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 0b107aac8b9..d6f6dbb2b10 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1579,7 +1579,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
* eraser region (either within stroke painted, or on its lines)
- * - this assumes that linewidth is irrelevant
+ * - this assumes that line-width is irrelevant.
*/
if (gpencil_stroke_inside_circle(mval, radius, pc0[0], pc0[1], pc2[0], pc2[1])) {
diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c
index 7ec64b2afd6..16605b6c634 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_paint.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c
@@ -910,7 +910,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
* brush region (either within stroke painted, or on its lines)
- * - this assumes that linewidth is irrelevant
+ * - this assumes that line-width is irrelevant.
*/
if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c
index 6e396cd82e3..d14322e12b5 100644
--- a/source/blender/editors/gpencil/gpencil_weight_paint.c
+++ b/source/blender/editors/gpencil/gpencil_weight_paint.c
@@ -448,7 +448,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
* brush region (either within stroke painted, or on its lines)
- * - this assumes that linewidth is irrelevant
+ * - this assumes that line-width is irrelevant.
*/
if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 0493832c06f..673f629d6ef 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -468,7 +468,7 @@ bool fcurve_is_changed(struct PointerRNA ptr,
* Checks whether a keyframe exists for the given ID-block one the given frame.
* - It is recommended to call this method over the other keyframe-checkers directly,
* in case some detail of the implementation changes...
- * - frame: the value of this is quite often result of #BKE_scene_frame_get()
+ * - frame: the value of this is quite often result of #BKE_scene_ctime_get()
*/
bool id_frame_has_keyframe(struct ID *id, float frame, short filter);
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 667540b8f63..2b73194afb2 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -86,7 +86,7 @@ void EDBM_mesh_clear(struct BMEditMesh *em);
void EDBM_selectmode_to_scene(struct bContext *C);
void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index);
-void EDBM_mesh_free(struct BMEditMesh *em);
+void EDBM_mesh_free_data(struct BMEditMesh *em);
void EDBM_mesh_load_ex(struct Main *bmain, struct Object *ob, bool free_data);
void EDBM_mesh_load(struct Main *bmain, struct Object *ob);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 7a8c14d0a35..802c175492f 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -58,6 +58,7 @@ struct bNodeTree;
struct bScreen;
struct rctf;
struct rcti;
+struct uiBlockInteraction_Handle;
struct uiButSearch;
struct uiFontStyle;
struct uiList;
@@ -245,7 +246,7 @@ enum {
#define UI_PANEL_BOX_STYLE_MARGIN (U.widget_unit * 0.2f)
/* but->drawflag - these flags should only affect how the button is drawn. */
-/* NOTE: currently, these flags _are not passed_ to the widget's state() or draw() functions
+/* NOTE: currently, these flags *are not passed* to the widget's state() or draw() functions
* (except for the 'align' ones)!
*/
enum {
@@ -514,6 +515,54 @@ typedef int (*uiButPushedStateFunc)(struct uiBut *but, const void *arg);
typedef void (*uiBlockHandleFunc)(struct bContext *C, void *arg, int event);
+/* -------------------------------------------------------------------- */
+/** \name Custom Interaction
+ *
+ * Sometimes it's useful to create data that remains available
+ * while the user interacts with a button.
+ *
+ * A common case is dragging a number button or slider
+ * however this could be used in other cases too.
+ * \{ */
+
+struct uiBlockInteraction_Params {
+ /**
+ * When true, this interaction is not modal
+ * (user clicking on a number button arrows or pasting a value for example).
+ */
+ bool is_click;
+ /**
+ * Array of unique event ID's (values from #uiBut.retval).
+ * There may be more than one for multi-button editing (see #UI_BUT_DRAG_MULTI).
+ */
+ int *unique_retval_ids;
+ uint unique_retval_ids_len;
+};
+
+/** Returns 'user_data', freed by #uiBlockInteractionEndFn. */
+typedef void *(*uiBlockInteractionBeginFn)(struct bContext *C,
+ const struct uiBlockInteraction_Params *params,
+ void *arg1);
+typedef void (*uiBlockInteractionEndFn)(struct bContext *C,
+ const struct uiBlockInteraction_Params *params,
+ void *arg1,
+ void *user_data);
+typedef void (*uiBlockInteractionUpdateFn)(struct bContext *C,
+ const struct uiBlockInteraction_Params *params,
+ void *arg1,
+ void *user_data);
+
+typedef struct uiBlockInteraction_CallbackData {
+ uiBlockInteractionBeginFn begin_fn;
+ uiBlockInteractionEndFn end_fn;
+ uiBlockInteractionUpdateFn update_fn;
+ void *arg1;
+} uiBlockInteraction_CallbackData;
+
+void UI_block_interaction_set(uiBlock *block, uiBlockInteraction_CallbackData *callbacks);
+
+/** \} */
+
/* Menu Callbacks */
typedef void (*uiMenuCreateFunc)(struct bContext *C, struct uiLayout *layout, void *arg1);
@@ -663,7 +712,7 @@ enum {
UI_BLOCK_THEME_STYLE_POPUP = 1,
};
void UI_block_theme_style_set(uiBlock *block, char theme_style);
-char UI_block_emboss_get(uiBlock *block);
+eUIEmbossType UI_block_emboss_get(uiBlock *block);
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss);
bool UI_block_is_search_only(const uiBlock *block);
void UI_block_set_search_only(uiBlock *block, bool search_only);
@@ -678,7 +727,7 @@ void UI_block_region_set(uiBlock *block, struct ARegion *region);
void UI_block_lock_set(uiBlock *block, bool val, const char *lockstr);
void UI_block_lock_clear(uiBlock *block);
-/* automatic aligning, horiz or verical */
+/* Automatic aligning, horizontal or vertical. */
void UI_block_align_begin(uiBlock *block);
void UI_block_align_end(uiBlock *block);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index e9784a59d70..32b86119753 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -3542,7 +3542,7 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, eU
return block;
}
-char UI_block_emboss_get(uiBlock *block)
+eUIEmbossType UI_block_emboss_get(uiBlock *block)
{
return block->emboss;
}
@@ -4106,7 +4106,6 @@ static uiBut *ui_def_but(uiBlock *block,
UI_BTYPE_BLOCK,
UI_BTYPE_BUT_MENU,
UI_BTYPE_SEARCH_MENU,
- UI_BTYPE_PROGRESS_BAR,
UI_BTYPE_DATASETROW,
UI_BTYPE_POPOVER)) {
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index de0d5a4a3d7..2a7611eabb1 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -560,7 +560,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
const bool is_overridable = (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE) != 0;
/* Set the (button_pointer, button_prop)
- * and pointer data for Python access to the hovered ui element. */
+ * and pointer data for Python access to the hovered UI element. */
uiLayoutSetContextFromBut(layout, but);
/* Keyframes */
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 2bd1b404228..655fdda3069 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -229,7 +229,7 @@ void ui_draw_but_TAB_outline(const rcti *rect,
{0.98, 0.805},
};
- /* mult */
+ /* Multiply. */
for (a = 0; a < 4; a++) {
mul_v2_fl(vec[a], rad);
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index bf81ccd280e..0e45970a165 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -35,10 +35,12 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "BLI_array_utils.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
+#include "BLI_sort_utils.h"
#include "BLI_string.h"
#include "BLI_string_cursor_utf8.h"
#include "BLI_string_utf8.h"
@@ -170,6 +172,20 @@ static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but
static void ui_textedit_string_set(uiBut *but, struct uiHandleButtonData *data, const char *str);
static void button_tooltip_timer_reset(bContext *C, uiBut *but);
+static void ui_block_interaction_begin_ensure(bContext *C,
+ uiBlock *block,
+ struct uiHandleButtonData *data,
+ const bool is_click);
+static struct uiBlockInteraction_Handle *ui_block_interaction_begin(struct bContext *C,
+ uiBlock *block,
+ const bool is_click);
+static void ui_block_interaction_end(struct bContext *C,
+ uiBlockInteraction_CallbackData *callbacks,
+ struct uiBlockInteraction_Handle *interaction);
+static void ui_block_interaction_update(struct bContext *C,
+ uiBlockInteraction_CallbackData *callbacks,
+ struct uiBlockInteraction_Handle *interaction);
+
#ifdef USE_KEYNAV_LIMIT
static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event);
static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEvent *event);
@@ -225,6 +241,19 @@ typedef enum uiMenuScrollType {
MENU_SCROLL_BOTTOM,
} uiMenuScrollType;
+typedef struct uiBlockInteraction_Handle {
+ struct uiBlockInteraction_Params params;
+ void *user_data;
+ /**
+ * This is shared between #uiHandleButtonData and #uiAfterFunc,
+ * the last user runs the end callback and frees the data.
+ *
+ * This is needed as the order of freeing changes depending on
+ * accepting/canceling the operation.
+ */
+ int user_count;
+} uiBlockInteraction_Handle;
+
#ifdef USE_ALLSELECT
/* Unfortunately there's no good way handle more generally:
@@ -430,6 +459,8 @@ typedef struct uiHandleButtonData {
uiSelectContextStore select_others;
#endif
+ struct uiBlockInteraction_Handle *custom_interaction_handle;
+
/* Text field undo. */
struct uiUndoStack_Text *undo_stack_text;
@@ -471,6 +502,9 @@ typedef struct uiAfterFunc {
void *search_arg;
uiFreeArgFunc search_arg_free_fn;
+ uiBlockInteraction_CallbackData custom_interaction_callbacks;
+ uiBlockInteraction_Handle *custom_interaction_handle;
+
bContextStore *context;
char undostr[BKE_UNDO_STR_MAX];
@@ -769,72 +803,95 @@ static bool ui_afterfunc_check(const uiBlock *block, const uiBut *but)
(block->handle && block->handle->popup_op));
}
+/**
+ * These functions are postponed and only executed after all other
+ * handling is done, i.e. menus are closed, in order to avoid conflicts
+ * with these functions removing the buttons we are working with.
+ */
static void ui_apply_but_func(bContext *C, uiBut *but)
{
uiBlock *block = but->block;
+ if (!ui_afterfunc_check(block, but)) {
+ return;
+ }
- /* these functions are postponed and only executed after all other
- * handling is done, i.e. menus are closed, in order to avoid conflicts
- * with these functions removing the buttons we are working with */
-
- if (ui_afterfunc_check(block, but)) {
- uiAfterFunc *after = ui_afterfunc_new();
+ uiAfterFunc *after = ui_afterfunc_new();
- if (but->func && ELEM(but, but->func_arg1, but->func_arg2)) {
- /* exception, this will crash due to removed button otherwise */
- but->func(C, but->func_arg1, but->func_arg2);
- }
- else {
- after->func = but->func;
- }
+ if (but->func && ELEM(but, but->func_arg1, but->func_arg2)) {
+ /* exception, this will crash due to removed button otherwise */
+ but->func(C, but->func_arg1, but->func_arg2);
+ }
+ else {
+ after->func = but->func;
+ }
- after->func_arg1 = but->func_arg1;
- after->func_arg2 = but->func_arg2;
+ after->func_arg1 = but->func_arg1;
+ after->func_arg2 = but->func_arg2;
- after->funcN = but->funcN;
- after->func_argN = (but->func_argN) ? MEM_dupallocN(but->func_argN) : NULL;
+ after->funcN = but->funcN;
+ after->func_argN = (but->func_argN) ? MEM_dupallocN(but->func_argN) : NULL;
- after->rename_func = but->rename_func;
- after->rename_arg1 = but->rename_arg1;
- after->rename_orig = but->rename_orig; /* needs free! */
+ after->rename_func = but->rename_func;
+ after->rename_arg1 = but->rename_arg1;
+ after->rename_orig = but->rename_orig; /* needs free! */
- after->handle_func = block->handle_func;
- after->handle_func_arg = block->handle_func_arg;
- after->retval = but->retval;
+ after->handle_func = block->handle_func;
+ after->handle_func_arg = block->handle_func_arg;
+ after->retval = but->retval;
- if (but->type == UI_BTYPE_BUT_MENU) {
- after->butm_func = block->butm_func;
- after->butm_func_arg = block->butm_func_arg;
- after->a2 = but->a2;
- }
+ if (but->type == UI_BTYPE_BUT_MENU) {
+ after->butm_func = block->butm_func;
+ after->butm_func_arg = block->butm_func_arg;
+ after->a2 = but->a2;
+ }
- if (block->handle) {
- after->popup_op = block->handle->popup_op;
- }
+ if (block->handle) {
+ after->popup_op = block->handle->popup_op;
+ }
- after->optype = but->optype;
- after->opcontext = but->opcontext;
- after->opptr = but->opptr;
+ after->optype = but->optype;
+ after->opcontext = but->opcontext;
+ after->opptr = but->opptr;
- after->rnapoin = but->rnapoin;
- after->rnaprop = but->rnaprop;
+ after->rnapoin = but->rnapoin;
+ after->rnaprop = but->rnaprop;
- if (but->type == UI_BTYPE_SEARCH_MENU) {
- uiButSearch *search_but = (uiButSearch *)but;
- after->search_arg_free_fn = search_but->arg_free_fn;
- after->search_arg = search_but->arg;
- search_but->arg_free_fn = NULL;
- search_but->arg = NULL;
- }
+ if (but->type == UI_BTYPE_SEARCH_MENU) {
+ uiButSearch *search_but = (uiButSearch *)but;
+ after->search_arg_free_fn = search_but->arg_free_fn;
+ after->search_arg = search_but->arg;
+ search_but->arg_free_fn = NULL;
+ search_but->arg = NULL;
+ }
- if (but->context) {
- after->context = CTX_store_copy(but->context);
+ if (but->active != NULL) {
+ uiHandleButtonData *data = but->active;
+ if (data->custom_interaction_handle != NULL) {
+ after->custom_interaction_callbacks = block->custom_interaction_callbacks;
+ after->custom_interaction_handle = data->custom_interaction_handle;
+
+ /* Ensure this callback runs once and last. */
+ uiAfterFunc *after_prev = after->prev;
+ if (after_prev &&
+ (after_prev->custom_interaction_handle == data->custom_interaction_handle)) {
+ after_prev->custom_interaction_handle = NULL;
+ memset(&after_prev->custom_interaction_callbacks,
+ 0x0,
+ sizeof(after_prev->custom_interaction_callbacks));
+ }
+ else {
+ after->custom_interaction_handle->user_count++;
+ }
}
+ }
- but->optype = NULL;
- but->opcontext = 0;
- but->opptr = NULL;
+ if (but->context) {
+ after->context = CTX_store_copy(but->context);
}
+
+ but->optype = NULL;
+ but->opcontext = 0;
+ but->opptr = NULL;
}
/* typically call ui_apply_but_undo(), ui_apply_but_autokey() */
@@ -997,6 +1054,18 @@ static void ui_apply_but_funcs_after(bContext *C)
after.search_arg_free_fn(after.search_arg);
}
+ if (after.custom_interaction_handle != NULL) {
+ after.custom_interaction_handle->user_count--;
+ BLI_assert(after.custom_interaction_handle->user_count >= 0);
+ if (after.custom_interaction_handle->user_count == 0) {
+ ui_block_interaction_update(
+ C, &after.custom_interaction_callbacks, after.custom_interaction_handle);
+ ui_block_interaction_end(
+ C, &after.custom_interaction_callbacks, after.custom_interaction_handle);
+ }
+ after.custom_interaction_handle = NULL;
+ }
+
ui_afterfunc_update_preferences_dirty(&after);
if (after.undostr[0]) {
@@ -2283,6 +2352,11 @@ static void ui_apply_but(
uiButCurveProfile *but_profile = (uiButCurveProfile *)but;
but_profile->edit_profile = editprofile;
}
+
+ if (data->custom_interaction_handle != NULL) {
+ ui_block_interaction_update(
+ C, &block->custom_interaction_callbacks, data->custom_interaction_handle);
+ }
}
/** \} */
@@ -3268,7 +3342,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
}
#ifdef WITH_INPUT_IME
-/* enable ime, and set up uibut ime data */
+/* Enable IME, and setup #uiBut IME data. */
static void ui_textedit_ime_begin(wmWindow *win, uiBut *UNUSED(but))
{
/* XXX Is this really needed? */
@@ -3284,7 +3358,7 @@ static void ui_textedit_ime_begin(wmWindow *win, uiBut *UNUSED(but))
wm_window_IME_begin(win, x, y, 0, 0, true);
}
-/* disable ime, and clear uibut ime data */
+/* Disable IME, and clear #uiBut IME data. */
static void ui_textedit_ime_end(wmWindow *win, uiBut *UNUSED(but))
{
wm_window_IME_end(win);
@@ -4852,6 +4926,8 @@ static bool ui_numedit_but_NUM(uiButNumber *number_but,
return changed;
}
+ ui_block_interaction_begin_ensure(but->block->evil_C, but->block, data, false);
+
if (ui_but_is_cursor_warp(but)) {
const float softmin = but->softmin;
const float softmax = but->softmax;
@@ -5362,6 +5438,8 @@ static bool ui_numedit_but_SLI(uiBut *but,
return changed;
}
+ ui_block_interaction_begin_ensure(but->block->evil_C, but->block, data, false);
+
const PropertyScaleType scale_type = ui_but_scale_type(but);
softmin = but->softmin;
@@ -8239,6 +8317,16 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
but->flag &= ~UI_SELECT;
}
+ if (state == BUTTON_STATE_TEXT_EDITING) {
+ ui_block_interaction_begin_ensure(C, but->block, data, true);
+ }
+ else if (state == BUTTON_STATE_EXIT) {
+ if (data->state == BUTTON_STATE_NUM_EDITING) {
+ /* This happens on pasting values for example. */
+ ui_block_interaction_begin_ensure(C, but->block, data, true);
+ }
+ }
+
data->state = state;
if (state != BUTTON_STATE_EXIT) {
@@ -8467,6 +8555,21 @@ static void button_activate_exit(
ED_region_tag_redraw_no_rebuild(data->region);
ED_region_tag_refresh_ui(data->region);
+ if ((but->flag & UI_BUT_DRAG_MULTI) == 0) {
+ if (data->custom_interaction_handle != NULL) {
+ /* Should only set when the button is modal. */
+ BLI_assert(but->active != NULL);
+ data->custom_interaction_handle->user_count--;
+
+ BLI_assert(data->custom_interaction_handle->user_count >= 0);
+ if (data->custom_interaction_handle->user_count == 0) {
+ ui_block_interaction_end(
+ C, &but->block->custom_interaction_callbacks, data->custom_interaction_handle);
+ }
+ data->custom_interaction_handle = NULL;
+ }
+ }
+
/* clean up button */
if (but->active) {
MEM_freeN(but->active);
@@ -11314,3 +11417,100 @@ bool UI_but_active_drop_color(bContext *C)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UI Block Interaction API
+ * \{ */
+
+void UI_block_interaction_set(uiBlock *block, uiBlockInteraction_CallbackData *callbacks)
+{
+ block->custom_interaction_callbacks = *callbacks;
+}
+
+static uiBlockInteraction_Handle *ui_block_interaction_begin(bContext *C,
+ uiBlock *block,
+ const bool is_click)
+{
+ BLI_assert(block->custom_interaction_callbacks.begin_fn != NULL);
+ uiBlockInteraction_Handle *interaction = MEM_callocN(sizeof(*interaction), __func__);
+
+ int unique_retval_ids_len = 0;
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->active || (but->flag & UI_BUT_DRAG_MULTI)) {
+ unique_retval_ids_len++;
+ }
+ }
+
+ int *unique_retval_ids = MEM_mallocN(sizeof(*unique_retval_ids) * unique_retval_ids_len,
+ __func__);
+ unique_retval_ids_len = 0;
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->active || (but->flag & UI_BUT_DRAG_MULTI)) {
+ unique_retval_ids[unique_retval_ids_len++] = but->retval;
+ }
+ }
+
+ if (unique_retval_ids_len > 1) {
+ qsort(unique_retval_ids, unique_retval_ids_len, sizeof(int), BLI_sortutil_cmp_int);
+ unique_retval_ids_len = BLI_array_deduplicate_ordered(unique_retval_ids,
+ unique_retval_ids_len);
+ unique_retval_ids = MEM_reallocN(unique_retval_ids,
+ sizeof(*unique_retval_ids) * unique_retval_ids_len);
+ }
+
+ interaction->params.is_click = is_click;
+ interaction->params.unique_retval_ids = unique_retval_ids;
+ interaction->params.unique_retval_ids_len = unique_retval_ids_len;
+
+ interaction->user_data = block->custom_interaction_callbacks.begin_fn(
+ C, &interaction->params, block->custom_interaction_callbacks.arg1);
+ return interaction;
+}
+
+static void ui_block_interaction_end(bContext *C,
+ uiBlockInteraction_CallbackData *callbacks,
+ uiBlockInteraction_Handle *interaction)
+{
+ BLI_assert(callbacks->end_fn != NULL);
+ callbacks->end_fn(C, &interaction->params, callbacks->arg1, interaction->user_data);
+ MEM_freeN(interaction->params.unique_retval_ids);
+ MEM_freeN(interaction);
+}
+
+static void ui_block_interaction_update(bContext *C,
+ uiBlockInteraction_CallbackData *callbacks,
+ uiBlockInteraction_Handle *interaction)
+{
+ BLI_assert(callbacks->update_fn != NULL);
+ callbacks->update_fn(C, &interaction->params, callbacks->arg1, interaction->user_data);
+}
+
+/**
+ * \note #ui_block_interaction_begin cannot be called when setting the button state
+ * (e.g. #BUTTON_STATE_NUM_EDITING) for the following reasons.
+ *
+ * - Other buttons may still be activated using #UI_BUT_DRAG_MULTI
+ * which is necessary before gathering all the #uiBut.retval values to initialize
+ * #uiBlockInteraction_Params.unique_retval_ids.
+ * - When clicking on a number button it's not known if the event is a click or a drag.
+ *
+ * Instead, it must be called immediately before the drag action begins.
+ */
+static void ui_block_interaction_begin_ensure(bContext *C,
+ uiBlock *block,
+ uiHandleButtonData *data,
+ const bool is_click)
+{
+ if (data->custom_interaction_handle) {
+ return;
+ }
+ if (block->custom_interaction_callbacks.begin_fn == NULL) {
+ return;
+ }
+
+ uiBlockInteraction_Handle *interaction = ui_block_interaction_begin(C, block, is_click);
+ interaction->user_count = 1;
+ data->custom_interaction_handle = interaction;
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index c9253e1f675..aa957afbf8f 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1519,7 +1519,7 @@ static void icon_draw_rect(float x,
draw_h = h;
draw_x += (w - draw_w) / 2;
}
- /* if the image is squared, the draw_ initialization values are good */
+ /* If the image is squared, the `draw_*` initialization values are good. */
/* first allocate imbuf for scaling and copy preview into it */
ima = IMB_allocImBuf(rw, rh, 32, IB_rect);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index a05afb6e542..40a9c67c630 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -511,6 +511,9 @@ struct uiBlock {
uiBlockHandleFunc handle_func;
void *handle_func_arg;
+ /** Custom interaction data. */
+ uiBlockInteraction_CallbackData custom_interaction_callbacks;
+
/** Custom extra event handling. */
int (*block_event_func)(const struct bContext *C, struct uiBlock *, const struct wmEvent *);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index abebc09ace2..8b9539f1d33 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1411,7 +1411,7 @@ BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout)
}
/**
- * Create ui items for enum items in \a item_array.
+ * Create UI items for enum items in \a item_array.
*
* A version of #uiItemsFullEnumO that takes pre-calculated item array.
*/
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index e85ec40ac73..9c17486aea4 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2399,8 +2399,8 @@ static eAutoPropButsReturn template_operator_property_buts_draw_single(
op->type->ui((bContext *)C, op);
op->layout = NULL;
- /* UI_LAYOUT_OP_SHOW_EMPTY ignored. retun_info is ignored too. We could
- * allow ot.ui callback to return this, but not needed right now. */
+ /* #UI_LAYOUT_OP_SHOW_EMPTY ignored. retun_info is ignored too.
+ * We could allow #wmOperatorType.ui callback to return this, but not needed right now. */
}
else {
wmWindowManager *wm = CTX_wm_manager(C);
@@ -4015,23 +4015,23 @@ static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
case UICURVE_FUNC_RESET_VIEW:
BKE_curvemapping_reset_view(cumap);
break;
- case UICURVE_FUNC_HANDLE_VECTOR: /* set vector */
+ case UICURVE_FUNC_HANDLE_VECTOR: /* Set vector. */
BKE_curvemap_handle_set(cuma, HD_VECT);
BKE_curvemapping_changed(cumap, false);
break;
- case UICURVE_FUNC_HANDLE_AUTO: /* set auto */
+ case UICURVE_FUNC_HANDLE_AUTO: /* Set auto. */
BKE_curvemap_handle_set(cuma, HD_AUTO);
BKE_curvemapping_changed(cumap, false);
break;
- case UICURVE_FUNC_HANDLE_AUTO_ANIM: /* set auto-clamped */
+ case UICURVE_FUNC_HANDLE_AUTO_ANIM: /* Set auto-clamped. */
BKE_curvemap_handle_set(cuma, HD_AUTO_ANIM);
BKE_curvemapping_changed(cumap, false);
break;
- case UICURVE_FUNC_EXTEND_HOZ: /* extend horiz */
+ case UICURVE_FUNC_EXTEND_HOZ: /* Extend horizontal. */
cumap->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
BKE_curvemapping_changed(cumap, false);
break;
- case UICURVE_FUNC_EXTEND_EXP: /* extend extrapolate */
+ case UICURVE_FUNC_EXTEND_EXP: /* Extend extrapolate. */
cumap->flag |= CUMA_EXTEND_EXTRAPOLATE;
BKE_curvemapping_changed(cumap, false);
break;
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 057c33c779c..7ea02226f02 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -701,7 +701,7 @@ int UI_calc_float_precision(int prec, double value)
/* Check on the number of decimal places need to display the number,
* this is so 0.00001 is not displayed as 0.00,
- * _but_, this is only for small values si 10.0001 will not get the same treatment.
+ * _but_, this is only for small values as 10.0001 will not get the same treatment.
*/
value = fabs(value);
if ((value < pow10_neg[prec]) && (value > (1.0 / max_pow))) {
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index f4d9c95ae09..72847fb2476 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1377,8 +1377,6 @@ static int ui_but_draw_menu_icon(const uiBut *but)
static void widget_draw_icon(
const uiBut *but, BIFIconID icon, float alpha, const rcti *rect, const uchar mono_color[4])
{
- float xs = 0.0f, ys = 0.0f;
-
if (but->flag & UI_BUT_ICON_PREVIEW) {
GPU_blend(GPU_BLEND_ALPHA);
widget_draw_preview(icon, alpha, rect);
@@ -1420,6 +1418,7 @@ static void widget_draw_icon(
if (icon && icon != ICON_BLANK1) {
const float ofs = 1.0f / aspect;
+ float xs, ys;
if (but->drawflag & UI_BUT_ICON_LEFT) {
/* special case - icon_only pie buttons */
@@ -2088,7 +2087,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
but_pos_ofs = but->pos;
#ifdef WITH_INPUT_IME
- /* if is ime compositing, move the cursor */
+ /* If is IME compositing, move the cursor. */
if (ime_data && ime_data->composite_len && ime_data->cursor_pos != -1) {
but_pos_ofs += ime_data->cursor_pos;
}
@@ -2140,12 +2139,12 @@ static void widget_draw_text(const uiFontStyle *fstyle,
}
#ifdef WITH_INPUT_IME
- /* ime cursor following */
+ /* IME cursor following. */
if (ime_reposition_window) {
ui_but_ime_reposition(but, ime_win_x, ime_win_y, false);
}
if (ime_data && ime_data->composite_len) {
- /* composite underline */
+ /* Composite underline. */
widget_draw_text_ime_underline(fstyle, wcol, but, rect, ime_data, drawstr);
}
#endif
@@ -3720,10 +3719,6 @@ static void widget_progressbar(
/* "slider" bar color */
copy_v3_v3_uchar(wcol->inner, wcol->item);
widgetbase_draw(&wtb_bar, wcol);
-
- /* raise text a bit */
- rect->xmin += (BLI_rcti_size_x(&rect_prog) / 2);
- rect->xmax += (BLI_rcti_size_x(&rect_prog) / 2);
}
static void widget_datasetrow(
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 73bcaee735e..1fd1b6c984d 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -1745,7 +1745,7 @@ typedef struct v2dScrollerMove {
* This is a CUT DOWN VERSION of the 'real' version, which is defined in view2d.c,
* as we only need focus bubble info.
*
- * \warning: The start of this struct must not change,
+ * \warning The start of this struct must not change,
* so that it stays in sync with the 'real' version.
* For now, we don't need to have a separate (internal) header for structs like this...
*/
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 28838d677f0..12890552b1d 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -63,10 +63,26 @@
# include "WM_api.h"
# include "WM_types.h"
+# include "DEG_depsgraph.h"
+
# include "io_alembic.h"
# include "ABC_alembic.h"
+const EnumPropertyItem rna_enum_abc_export_evaluation_mode_items[] = {
+ {DAG_EVAL_RENDER,
+ "RENDER",
+ 0,
+ "Render",
+ "Use Render settings for object visibility, modifier settings, etc"},
+ {DAG_EVAL_VIEWPORT,
+ "VIEWPORT",
+ 0,
+ "Viewport",
+ "Use Viewport settings for object visibility, modifier settings, etc"},
+ {0, NULL, 0, NULL, NULL},
+};
+
static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (!RNA_struct_property_is_set(op->ptr, "as_background_job")) {
@@ -126,7 +142,6 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
.curves_as_mesh = RNA_boolean_get(op->ptr, "curves_as_mesh"),
.flatten_hierarchy = RNA_boolean_get(op->ptr, "flatten"),
.visible_objects_only = RNA_boolean_get(op->ptr, "visible_objects_only"),
- .renderable_only = RNA_boolean_get(op->ptr, "renderable_only"),
.face_sets = RNA_boolean_get(op->ptr, "face_sets"),
.use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"),
.export_hair = RNA_boolean_get(op->ptr, "export_hair"),
@@ -137,6 +152,7 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
.triangulate = RNA_boolean_get(op->ptr, "triangulate"),
.quad_method = RNA_enum_get(op->ptr, "quad_method"),
.ngon_method = RNA_enum_get(op->ptr, "ngon_method"),
+ .evaluation_mode = RNA_enum_get(op->ptr, "evaluation_mode"),
.global_scale = RNA_float_get(op->ptr, "global_scale"),
};
@@ -194,9 +210,11 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
sub = uiLayoutColumnWithHeading(col, true, IFACE_("Only"));
uiItemR(sub, imfptr, "selected", 0, IFACE_("Selected Objects"), ICON_NONE);
- uiItemR(sub, imfptr, "renderable_only", 0, IFACE_("Renderable Objects"), ICON_NONE);
uiItemR(sub, imfptr, "visible_objects_only", 0, IFACE_("Visible Objects"), ICON_NONE);
+ col = uiLayoutColumn(box, true);
+ uiItemR(col, imfptr, "evaluation_mode", 0, NULL, ICON_NONE);
+
/* Object Data */
box = uiLayoutBox(layout);
row = uiLayoutRow(box, false);
@@ -355,12 +373,6 @@ void WM_OT_alembic_export(wmOperatorType *ot)
ot->srna, "selected", 0, "Selected Objects Only", "Export only selected objects");
RNA_def_boolean(ot->srna,
- "renderable_only",
- 1,
- "Renderable Objects Only",
- "Export only objects marked renderable in the outliner");
-
- RNA_def_boolean(ot->srna,
"visible_objects_only",
0,
"Visible Objects Only",
@@ -468,6 +480,14 @@ void WM_OT_alembic_export(wmOperatorType *ot)
"This option is deprecated; EXECUTE this operator to run in the foreground, and INVOKE it "
"to run as a background job");
+ RNA_def_enum(ot->srna,
+ "evaluation_mode",
+ rna_enum_abc_export_evaluation_mode_items,
+ DAG_EVAL_RENDER,
+ "Use Settings for",
+ "Determines visibility of objects, modifier settings, and other areas where there "
+ "are different settings for viewport and rendering");
+
/* This dummy prop is used to check whether we need to init the start and
* end frame values to that of the scene's, otherwise they are reset at
* every change, draw update. */
diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
index d92a81179cc..23eaf991fd3 100644
--- a/source/blender/editors/lattice/editlattice_undo.c
+++ b/source/blender/editors/lattice/editlattice_undo.c
@@ -240,7 +240,7 @@ static void lattice_undosys_step_decode(struct bContext *C,
}
undolatt_to_editlatt(&elem->data, lt->editlatt);
lt->editlatt->needs_flush_to_id = 1;
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&lt->id, ID_RECALC_GEOMETRY);
}
/* The first element is always active */
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index 942fe143787..09b17acf56d 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -30,6 +30,7 @@
#include "BKE_context.h"
#include "BKE_curve.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 993905462db..cccfc7e934c 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -126,7 +126,7 @@ static int geometry_extract_apply(bContext *C,
.calc_face_normal = true,
}));
- BMEditMesh *em = BKE_editmesh_create(bm, false);
+ BMEditMesh *em = BKE_editmesh_create(bm);
/* Generate the tags for deleting geometry in the extracted object. */
tag_fn(bm, params);
@@ -206,7 +206,7 @@ static int geometry_extract_apply(bContext *C,
}),
mesh);
- BKE_editmesh_free(em);
+ BKE_editmesh_free_data(em);
MEM_freeN(em);
if (new_mesh->totvert == 0) {
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 593545ddcef..30a453a32ee 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -29,6 +29,7 @@
#include "DNA_windowmanager_types.h"
#ifdef WITH_FREESTYLE
+# include "BKE_customdata.h"
# include "DNA_meshdata_types.h"
#endif
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 132a442343c..830c9abb41e 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -35,6 +35,7 @@
#include "BLI_utildefines_stack.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index f52ab48785d..c452f7a7487 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -29,6 +29,7 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 4d383140d80..41a9f426798 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -44,6 +44,7 @@
#include "BLI_string.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_key.h"
@@ -973,7 +974,7 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
#ifdef USE_FACE_CREATE_SEL_EXTEND
/* normally we would want to leave the new geometry selected,
* but being able to press F many times to add geometry is too useful! */
- if (ele_desel && (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) &&
+ if (ele_desel && (BMO_slot_buffer_len(bmop.slots_out, "faces.out") == 1) &&
(ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out"))) {
edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face);
}
@@ -2344,7 +2345,7 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
BMO_slot_buffer_hflag_enable(
em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
- const int tot_rotate = BMO_slot_buffer_count(bmop.slots_out, "edges.out");
+ const int tot_rotate = BMO_slot_buffer_len(bmop.slots_out, "edges.out");
const int tot_failed = tot - tot_rotate;
tot_rotate_all += tot_rotate;
@@ -6560,7 +6561,7 @@ enum {
typedef struct BMElemSort {
/** Sort factor */
float srt;
- /** Original index of this element _in its mempool_ */
+ /** Original index of this element (in its #BLI_mempool). */
int org_idx;
} BMElemSort;
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 112de68b52c..fc9e1aa8b1a 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -33,6 +33,7 @@
#include "BLI_listbase.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_key.h"
#include "BKE_layer.h"
@@ -671,7 +672,7 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key *
em->bm->shapenr = um->shapenr;
- EDBM_mesh_free(em);
+ EDBM_mesh_free_data(em);
bm = BM_mesh_create(&allocsize,
&((struct BMeshCreateParams){
@@ -681,13 +682,21 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key *
BM_mesh_bm_from_me(bm,
&um->me,
(&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
+ /* Handled with tessellation. */
+ .calc_face_normal = false,
.active_shapekey = um->shapenr,
}));
- em_tmp = BKE_editmesh_create(bm, true);
+ em_tmp = BKE_editmesh_create(bm);
*em = *em_tmp;
+ /* Calculate face normals and tessellation at once since it's multi-threaded.
+ * The vertex normals are stored in the undo-mesh, so this doesn't need to be updated. */
+ BKE_editmesh_looptri_calc_ex(em,
+ &(const struct BMeshCalcTessellation_Params){
+ .face_normals = true,
+ });
+
em->selectmode = um->selectmode;
bm->selectmode = um->selectmode;
@@ -865,7 +874,7 @@ static void mesh_undosys_step_decode(struct bContext *C,
BMEditMesh *em = me->edit_mesh;
undomesh_to_editmesh(&elem->data, obedit, em, me->key);
em->needs_flush_to_id = 1;
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
}
/* The first element is always active */
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 4f416c94f62..85c646d689c 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -305,17 +305,13 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
if (me->edit_mesh) {
/* this happens when switching shape keys */
- EDBM_mesh_free(me->edit_mesh);
+ EDBM_mesh_free_data(me->edit_mesh);
MEM_freeN(me->edit_mesh);
}
- /* currently executing operators re-tessellates, so we can avoid doing here
- * but at some point it may need to be added back. */
-#if 0
- me->edit_mesh = BKE_editmesh_create(bm, true);
-#else
- me->edit_mesh = BKE_editmesh_create(bm, false);
-#endif
+ /* Executing operators re-tessellates,
+ * so we can avoid doing here but at some point it may need to be added back. */
+ me->edit_mesh = BKE_editmesh_create(bm);
me->edit_mesh->selectmode = me->edit_mesh->bm->selectmode = select_mode;
me->edit_mesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0;
@@ -326,7 +322,8 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
/**
* \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates).
- * Most callers should run #DEG_id_tag_update on \a ob->data, see: T46738, T46913
+ * Most callers should run #DEG_id_tag_update on `ob->data`, see: T46738, T46913.
+ * This ensures #BKE_object_free_derived_caches runs on all objects that use this mesh.
*/
void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
{
@@ -346,25 +343,6 @@ void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
.calc_object_remap = true,
.update_shapekey_indices = !free_data,
}));
-
- /* Free derived mesh. usually this would happen through depsgraph but there
- * are exceptions like file save that will not cause this, and we want to
- * avoid ending up with an invalid derived mesh then.
- *
- * Do it for all objects which shares the same mesh datablock, since their
- * derived meshes might also be referencing data which was just freed,
- *
- * Annoying enough, but currently seems most efficient way to avoid access
- * of freed data on scene update, especially in cases when there are dependency
- * cycles.
- */
-#if 0
- for (Object *other_object = bmain->objects.first; other_object != NULL; other_object = other_object->id.next) {
- if (other_object->data == ob->data) {
- BKE_object_free_derived_caches(other_object);
- }
- }
-#endif
}
void EDBM_mesh_clear(BMEditMesh *em)
@@ -372,8 +350,8 @@ void EDBM_mesh_clear(BMEditMesh *em)
/* clear bmesh */
BM_mesh_clear(em->bm);
- /* free derived meshes */
- BKE_editmesh_free_derivedmesh(em);
+ /* Free evaluated meshes & cache. */
+ BKE_editmesh_free_derived_caches(em);
/* free tessellation data */
em->tottri = 0;
@@ -389,9 +367,9 @@ void EDBM_mesh_load(Main *bmain, Object *ob)
}
/**
- * Should only be called on the active editmesh, otherwise call #BKE_editmesh_free
+ * Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data.
*/
-void EDBM_mesh_free(BMEditMesh *em)
+void EDBM_mesh_free_data(BMEditMesh *em)
{
/* These tables aren't used yet, so it's not strictly necessary
* to 'end' them but if someone tries to start using them,
@@ -399,7 +377,7 @@ void EDBM_mesh_free(BMEditMesh *em)
ED_mesh_mirror_spatial_table_end(NULL);
ED_mesh_mirror_topo_table_end(NULL);
- BKE_editmesh_free(em);
+ BKE_editmesh_free_data(em);
}
/** \} */
@@ -1471,8 +1449,8 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
BM_lnorspace_invalidate(em->bm, false);
em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET;
}
- /* don't keep stale derivedMesh data around, see: T38872. */
- BKE_editmesh_free_derivedmesh(em);
+ /* Don't keep stale evaluated mesh data around, see: T38872. */
+ BKE_editmesh_free_derived_caches(em);
#ifdef DEBUG
{
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 2b78d83a9f5..73b3fb9724e 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -34,6 +34,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
index a8b471a7c92..f7b53b5513f 100644
--- a/source/blender/editors/metaball/editmball_undo.c
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -215,7 +215,7 @@ static void mball_undosys_step_decode(struct bContext *C,
}
undomball_to_editmball(&elem->data, mb);
mb->needs_flush_to_id = 1;
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&mb->id, ID_RECALC_GEOMETRY);
}
/* The first element is always active */
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 6d22da2c2bc..8ae74fbfafa 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1845,7 +1845,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
* ready to be moved around to re-time the sound and/or make new sound clips. */
{
/* create new data for NLA hierarchy */
- AnimData *adt = BKE_animdata_add_id(&ob->id);
+ AnimData *adt = BKE_animdata_ensure_id(&ob->id);
NlaTrack *nlt = BKE_nlatrack_add(adt, NULL, is_liboverride);
NlaStrip *strip = BKE_nla_add_soundstrip(bmain, scene, ob->data);
strip->start = CFRA;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 1cb6a5c8ff5..6108691b2f1 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -557,7 +557,7 @@ static bool ED_object_editmode_load_free_ex(Main *bmain,
}
if (free_data) {
- EDBM_mesh_free(me->edit_mesh);
+ EDBM_mesh_free_data(me->edit_mesh);
MEM_freeN(me->edit_mesh);
me->edit_mesh = NULL;
}
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 30f75e9a150..d7177eabcba 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2061,6 +2061,23 @@ static void single_object_action_users(
FOREACH_OBJECT_FLAG_END;
}
+static void single_objectdata_action_users(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag)
+{
+ FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) {
+ if (!ID_IS_LINKED(ob) && ob->data != NULL) {
+ ID *id_obdata = (ID *)ob->data;
+ AnimData *adt = BKE_animdata_from_id(id_obdata);
+ ID *id_act = (ID *)adt->action;
+ if (id_act && id_act->us > 1) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ BKE_animdata_copy_id_action(bmain, id_obdata);
+ }
+ }
+ }
+ FOREACH_OBJECT_FLAG_END;
+}
+
static void single_mat_users(
Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag)
{
@@ -2643,6 +2660,10 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
single_object_action_users(bmain, scene, view_layer, v3d, flag);
}
+ if (RNA_boolean_get(op->ptr, "obdata_animation")) {
+ single_objectdata_action_users(bmain, scene, view_layer, v3d, flag);
+ }
+
BKE_main_id_newptr_and_tag_clear(bmain);
WM_event_add_notifier(C, NC_WINDOW, NULL);
@@ -2684,8 +2705,16 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects");
RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data");
RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each data-block");
- RNA_def_boolean(
- ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object");
+ RNA_def_boolean(ot->srna,
+ "animation",
+ 0,
+ "Object Animation",
+ "Make object animation data local to each object");
+ RNA_def_boolean(ot->srna,
+ "obdata_animation",
+ 0,
+ "Object Data Animation",
+ "Make object data (mesh, curve etc.) animation data local to each object");
}
/** \} */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index e350653e178..4c4727f51ee 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1152,51 +1152,53 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
for (int object_index = 0; object_index < num_objects; object_index++) {
Object *ob = objects[object_index];
+ if (ob->flag & OB_DONE) {
+ continue;
+ }
- if ((ob->flag & OB_DONE) == 0) {
- bool do_inverse_offset = false;
- ob->flag |= OB_DONE;
+ bool do_inverse_offset = false;
+ ob->flag |= OB_DONE;
- if (centermode == ORIGIN_TO_CURSOR) {
- copy_v3_v3(cent, cursor);
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->imat, cent);
- }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ copy_v3_v3(cent, cursor);
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->imat, cent);
+ }
- if (ob->data == NULL) {
- /* special support for dupligroups */
- if ((ob->transflag & OB_DUPLICOLLECTION) && ob->instance_collection &&
- (ob->instance_collection->id.tag & LIB_TAG_DOIT) == 0) {
- if (ID_IS_LINKED(ob->instance_collection)) {
- tot_lib_error++;
+ if (ob->data == NULL) {
+ /* special support for dupligroups */
+ if ((ob->transflag & OB_DUPLICOLLECTION) && ob->instance_collection &&
+ (ob->instance_collection->id.tag & LIB_TAG_DOIT) == 0) {
+ if (ID_IS_LINKED(ob->instance_collection)) {
+ tot_lib_error++;
+ }
+ else {
+ if (centermode == ORIGIN_TO_CURSOR) {
+ /* done */
}
else {
- if (centermode == ORIGIN_TO_CURSOR) {
- /* done */
- }
- else {
- float min[3], max[3];
- /* only bounds support */
- INIT_MINMAX(min, max);
- BKE_object_minmax_dupli(depsgraph, scene, ob, min, max, true);
- mid_v3_v3v3(cent, min, max);
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->imat, cent);
- }
+ float min[3], max[3];
+ /* only bounds support */
+ INIT_MINMAX(min, max);
+ BKE_object_minmax_dupli(depsgraph, scene, ob, min, max, true);
+ mid_v3_v3v3(cent, min, max);
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->imat, cent);
+ }
- add_v3_v3(ob->instance_collection->instance_offset, cent);
+ add_v3_v3(ob->instance_collection->instance_offset, cent);
- tot_change++;
- ob->instance_collection->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
- }
+ tot_change++;
+ ob->instance_collection->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
}
}
- else if (ID_IS_LINKED(ob->data)) {
- tot_lib_error++;
- }
-
- if (obedit == NULL && ob->type == OB_MESH) {
+ }
+ else if (ID_IS_LINKED(ob->data)) {
+ tot_lib_error++;
+ }
+ else if (ob->type == OB_MESH) {
+ if (obedit == NULL) {
Mesh *me = ob->data;
if (centermode == ORIGIN_TO_CURSOR) {
@@ -1222,265 +1224,265 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
me->id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
}
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
- Curve *cu = ob->data;
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) {
- /* done */
- }
- else if (around == V3D_AROUND_CENTER_BOUNDS) {
- BKE_curve_center_bounds(cu, cent);
- }
- else { /* #V3D_AROUND_CENTER_MEDIAN. */
- BKE_curve_center_median(cu, cent);
- }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ /* done */
+ }
+ else if (around == V3D_AROUND_CENTER_BOUNDS) {
+ BKE_curve_center_bounds(cu, cent);
+ }
+ else { /* #V3D_AROUND_CENTER_MEDIAN. */
+ BKE_curve_center_median(cu, cent);
+ }
- /* don't allow Z change if curve is 2D */
- if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) {
- cent[2] = 0.0;
- }
+ /* don't allow Z change if curve is 2D */
+ if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) {
+ cent[2] = 0.0;
+ }
- negate_v3_v3(cent_neg, cent);
- BKE_curve_translate(cu, cent_neg, 1);
+ negate_v3_v3(cent_neg, cent);
+ BKE_curve_translate(cu, cent_neg, 1);
- tot_change++;
- cu->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
+ tot_change++;
+ cu->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
- if (obedit) {
- if (centermode == GEOMETRY_TO_ORIGIN) {
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
- }
- break;
+ if (obedit) {
+ if (centermode == GEOMETRY_TO_ORIGIN) {
+ DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
}
+ break;
}
- else if (ob->type == OB_FONT) {
- /* Get from bounding-box. */
+ }
+ else if (ob->type == OB_FONT) {
+ /* Get from bounding-box. */
- Curve *cu = ob->data;
+ Curve *cu = ob->data;
- if (ob->runtime.bb == NULL && (centermode != ORIGIN_TO_CURSOR)) {
- /* Do nothing. */
+ if (ob->runtime.bb == NULL && (centermode != ORIGIN_TO_CURSOR)) {
+ /* Do nothing. */
+ }
+ else {
+ if (centermode == ORIGIN_TO_CURSOR) {
+ /* Done. */
}
else {
- if (centermode == ORIGIN_TO_CURSOR) {
- /* Done. */
- }
- else {
- /* extra 0.5 is the height o above line */
- cent[0] = 0.5f * (ob->runtime.bb->vec[4][0] + ob->runtime.bb->vec[0][0]);
- cent[1] = 0.5f * (ob->runtime.bb->vec[0][1] + ob->runtime.bb->vec[2][1]);
- }
+ /* extra 0.5 is the height o above line */
+ cent[0] = 0.5f * (ob->runtime.bb->vec[4][0] + ob->runtime.bb->vec[0][0]);
+ cent[1] = 0.5f * (ob->runtime.bb->vec[0][1] + ob->runtime.bb->vec[2][1]);
+ }
- cent[2] = 0.0f;
+ cent[2] = 0.0f;
- cu->xof = cu->xof - cent[0];
- cu->yof = cu->yof - cent[1];
+ cu->xof = cu->xof - cent[0];
+ cu->yof = cu->yof - cent[1];
- tot_change++;
- cu->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
- }
+ tot_change++;
+ cu->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
}
- else if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
+ }
+ else if (ob->type == OB_ARMATURE) {
+ bArmature *arm = ob->data;
- if (ID_REAL_USERS(arm) > 1) {
+ if (ID_REAL_USERS(arm) > 1) {
#if 0
BKE_report(op->reports, RPT_ERROR, "Cannot apply to a multi user armature");
return;
#endif
- tot_multiuser_arm_error++;
- }
- else {
- /* Function to recenter armatures in editarmature.c
- * Bone + object locations are handled there.
- */
- ED_armature_origin_set(bmain, ob, cursor, centermode, around);
+ tot_multiuser_arm_error++;
+ }
+ else {
+ /* Function to recenter armatures in editarmature.c
+ * Bone + object locations are handled there.
+ */
+ ED_armature_origin_set(bmain, ob, cursor, centermode, around);
- tot_change++;
- arm->id.tag |= LIB_TAG_DOIT;
- /* do_inverse_offset = true; */ /* docenter_armature() handles this */
+ tot_change++;
+ arm->id.tag |= LIB_TAG_DOIT;
+ /* do_inverse_offset = true; */ /* docenter_armature() handles this */
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- BKE_object_transform_copy(ob_eval, ob);
- BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
- BKE_object_where_is_calc(depsgraph, scene, ob_eval);
- BKE_pose_where_is(depsgraph, scene, ob_eval); /* needed for bone parents */
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ BKE_object_transform_copy(ob_eval, ob);
+ BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
+ BKE_object_where_is_calc(depsgraph, scene, ob_eval);
+ BKE_pose_where_is(depsgraph, scene, ob_eval); /* needed for bone parents */
- ignore_parent_tx(bmain, depsgraph, scene, ob);
+ ignore_parent_tx(bmain, depsgraph, scene, ob);
- if (obedit) {
- break;
- }
+ if (obedit) {
+ break;
}
}
- else if (ob->type == OB_MBALL) {
- MetaBall *mb = ob->data;
+ }
+ else if (ob->type == OB_MBALL) {
+ MetaBall *mb = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) {
- /* done */
- }
- else if (around == V3D_AROUND_CENTER_BOUNDS) {
- BKE_mball_center_bounds(mb, cent);
- }
- else { /* #V3D_AROUND_CENTER_MEDIAN. */
- BKE_mball_center_median(mb, cent);
- }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ /* done */
+ }
+ else if (around == V3D_AROUND_CENTER_BOUNDS) {
+ BKE_mball_center_bounds(mb, cent);
+ }
+ else { /* #V3D_AROUND_CENTER_MEDIAN. */
+ BKE_mball_center_median(mb, cent);
+ }
- negate_v3_v3(cent_neg, cent);
- BKE_mball_translate(mb, cent_neg);
+ negate_v3_v3(cent_neg, cent);
+ BKE_mball_translate(mb, cent_neg);
- tot_change++;
- mb->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
+ tot_change++;
+ mb->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
- if (obedit) {
- if (centermode == GEOMETRY_TO_ORIGIN) {
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
- }
- break;
+ if (obedit) {
+ if (centermode == GEOMETRY_TO_ORIGIN) {
+ DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
}
+ break;
}
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = ob->data;
+ }
+ else if (ob->type == OB_LATTICE) {
+ Lattice *lt = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) {
- /* done */
- }
- else if (around == V3D_AROUND_CENTER_BOUNDS) {
- BKE_lattice_center_bounds(lt, cent);
- }
- else { /* #V3D_AROUND_CENTER_MEDIAN. */
- BKE_lattice_center_median(lt, cent);
- }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ /* done */
+ }
+ else if (around == V3D_AROUND_CENTER_BOUNDS) {
+ BKE_lattice_center_bounds(lt, cent);
+ }
+ else { /* #V3D_AROUND_CENTER_MEDIAN. */
+ BKE_lattice_center_median(lt, cent);
+ }
- negate_v3_v3(cent_neg, cent);
- BKE_lattice_translate(lt, cent_neg, 1);
+ negate_v3_v3(cent_neg, cent);
+ BKE_lattice_translate(lt, cent_neg, 1);
- tot_change++;
- lt->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
- }
- else if (ob->type == OB_GPENCIL) {
- bGPdata *gpd = ob->data;
- float gpcenter[3];
- if (gpd) {
- if (centermode == ORIGIN_TO_GEOMETRY) {
- zero_v3(gpcenter);
- BKE_gpencil_centroid_3d(gpd, gpcenter);
- add_v3_v3(gpcenter, ob->obmat[3]);
- }
- if (centermode == ORIGIN_TO_CURSOR) {
- copy_v3_v3(gpcenter, cursor);
- }
- if (ELEM(centermode, ORIGIN_TO_GEOMETRY, ORIGIN_TO_CURSOR)) {
- bGPDspoint *pt;
- float imat[3][3], bmat[3][3];
- float offset_global[3];
- float offset_local[3];
- int i;
-
- sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]);
- copy_m3_m4(bmat, obact->obmat);
- invert_m3_m3(imat, bmat);
- mul_m3_v3(imat, offset_global);
- mul_v3_m3v3(offset_local, imat, offset_global);
-
- float diff_mat[4][4];
- float inverse_diff_mat[4][4];
-
- /* recalculate all strokes
- * (all layers are considered without evaluating lock attributes) */
- LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
- /* calculate difference matrix */
- BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
- /* undo matrix */
- invert_m4_m4(inverse_diff_mat, diff_mat);
- LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
- LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- float mpt[3];
- mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
- sub_v3_v3(mpt, offset_local);
- mul_v3_m4v3(&pt->x, diff_mat, mpt);
- }
+ tot_change++;
+ lt->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
+ }
+ else if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = ob->data;
+ float gpcenter[3];
+ if (gpd) {
+ if (centermode == ORIGIN_TO_GEOMETRY) {
+ zero_v3(gpcenter);
+ BKE_gpencil_centroid_3d(gpd, gpcenter);
+ add_v3_v3(gpcenter, ob->obmat[3]);
+ }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ copy_v3_v3(gpcenter, cursor);
+ }
+ if (ELEM(centermode, ORIGIN_TO_GEOMETRY, ORIGIN_TO_CURSOR)) {
+ bGPDspoint *pt;
+ float imat[3][3], bmat[3][3];
+ float offset_global[3];
+ float offset_local[3];
+ int i;
+
+ sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]);
+ copy_m3_m4(bmat, obact->obmat);
+ invert_m3_m3(imat, bmat);
+ mul_m3_v3(imat, offset_global);
+ mul_v3_m3v3(offset_local, imat, offset_global);
+
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+
+ /* recalculate all strokes
+ * (all layers are considered without evaluating lock attributes) */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ /* calculate difference matrix */
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
+ /* undo matrix */
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float mpt[3];
+ mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
+ sub_v3_v3(mpt, offset_local);
+ mul_v3_m4v3(&pt->x, diff_mat, mpt);
}
}
}
- tot_change++;
- if (centermode == ORIGIN_TO_GEOMETRY) {
- copy_v3_v3(ob->loc, gpcenter);
- }
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
-
- ob->id.tag |= LIB_TAG_DOIT;
- do_inverse_offset = true;
}
- else {
- BKE_report(op->reports,
- RPT_WARNING,
- "Grease Pencil Object does not support this set origin option");
+ tot_change++;
+ if (centermode == ORIGIN_TO_GEOMETRY) {
+ copy_v3_v3(ob->loc, gpcenter);
}
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+
+ ob->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
+ }
+ else {
+ BKE_report(op->reports,
+ RPT_WARNING,
+ "Grease Pencil Object does not support this set origin option");
}
}
+ }
- /* offset other selected objects */
- if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) {
- float obmat[4][4];
+ /* offset other selected objects */
+ if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) {
+ float obmat[4][4];
- /* was the object data modified
- * NOTE: the functions above must set 'cent'. */
+ /* was the object data modified
+ * NOTE: the functions above must set 'cent'. */
- /* convert the offset to parent space */
- BKE_object_to_mat4(ob, obmat);
- mul_v3_mat3_m4v3(centn, obmat, cent); /* omit translation part */
+ /* convert the offset to parent space */
+ BKE_object_to_mat4(ob, obmat);
+ mul_v3_mat3_m4v3(centn, obmat, cent); /* omit translation part */
- add_v3_v3(ob->loc, centn);
+ add_v3_v3(ob->loc, centn);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- BKE_object_transform_copy(ob_eval, ob);
- BKE_object_where_is_calc(depsgraph, scene, ob_eval);
- if (ob->type == OB_ARMATURE) {
- /* needed for bone parents */
- BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
- BKE_pose_where_is(depsgraph, scene, ob_eval);
- }
-
- ignore_parent_tx(bmain, depsgraph, scene, ob);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ BKE_object_transform_copy(ob_eval, ob);
+ BKE_object_where_is_calc(depsgraph, scene, ob_eval);
+ if (ob->type == OB_ARMATURE) {
+ /* needed for bone parents */
+ BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
+ BKE_pose_where_is(depsgraph, scene, ob_eval);
+ }
- /* other users? */
- // CTX_DATA_BEGIN (C, Object *, ob_other, selected_editable_objects)
- //{
-
- /* use existing context looper */
- for (int other_object_index = 0; other_object_index < num_objects; other_object_index++) {
- Object *ob_other = objects[other_object_index];
-
- if ((ob_other->flag & OB_DONE) == 0 &&
- ((ob->data && (ob->data == ob_other->data)) ||
- (ob->instance_collection == ob_other->instance_collection &&
- (ob->transflag | ob_other->transflag) & OB_DUPLICOLLECTION))) {
- ob_other->flag |= OB_DONE;
- DEG_id_tag_update(&ob_other->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-
- mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */
- add_v3_v3(ob_other->loc, centn);
-
- Object *ob_other_eval = DEG_get_evaluated_object(depsgraph, ob_other);
- BKE_object_transform_copy(ob_other_eval, ob_other);
- BKE_object_where_is_calc(depsgraph, scene, ob_other_eval);
- if (ob_other->type == OB_ARMATURE) {
- /* needed for bone parents */
- BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
- BKE_pose_where_is(depsgraph, scene, ob_other_eval);
- }
- ignore_parent_tx(bmain, depsgraph, scene, ob_other);
+ ignore_parent_tx(bmain, depsgraph, scene, ob);
+
+ /* other users? */
+ // CTX_DATA_BEGIN (C, Object *, ob_other, selected_editable_objects)
+ //{
+
+ /* use existing context looper */
+ for (int other_object_index = 0; other_object_index < num_objects; other_object_index++) {
+ Object *ob_other = objects[other_object_index];
+
+ if ((ob_other->flag & OB_DONE) == 0 &&
+ ((ob->data && (ob->data == ob_other->data)) ||
+ (ob->instance_collection == ob_other->instance_collection &&
+ (ob->transflag | ob_other->transflag) & OB_DUPLICOLLECTION))) {
+ ob_other->flag |= OB_DONE;
+ DEG_id_tag_update(&ob_other->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+
+ mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */
+ add_v3_v3(ob_other->loc, centn);
+
+ Object *ob_other_eval = DEG_get_evaluated_object(depsgraph, ob_other);
+ BKE_object_transform_copy(ob_other_eval, ob_other);
+ BKE_object_where_is_calc(depsgraph, scene, ob_other_eval);
+ if (ob_other->type == OB_ARMATURE) {
+ /* needed for bone parents */
+ BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
+ BKE_pose_where_is(depsgraph, scene, ob_other_eval);
}
+ ignore_parent_tx(bmain, depsgraph, scene, ob_other);
}
- // CTX_DATA_END;
}
+ // CTX_DATA_END;
}
}
MEM_freeN(objects);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index c591931805d..39de63c22a9 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1539,8 +1539,8 @@ static void region_rect_recursive(
region->winx = BLI_rcti_size_x(&region->winrct) + 1;
region->winy = BLI_rcti_size_y(&region->winrct) + 1;
- /* if region opened normally, we store this for hide/reveal usage */
- /* prevent rounding errors for UI_DPI_FAC mult and divide */
+ /* If region opened normally, we store this for hide/reveal usage. */
+ /* Prevent rounding errors for UI_DPI_FAC multiply and divide. */
if (region->winx > 1) {
region->sizex = (region->winx + 0.5f) / UI_DPI_FAC;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index a888958b9be..bd05d309421 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -2052,7 +2052,7 @@ static bool line_clip_rect2f(const rctf *cliprect,
float l2_clip[2])
{
/* first account for horizontal, then vertical lines */
- /* horiz */
+ /* Horizontal. */
if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
/* is the line out of range on its Y axis? */
if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index da34723eed4..d968b6cc319 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -293,8 +293,8 @@ typedef struct SculptGestureContext {
/* These store the view origin and normal in world space, which is used in some gestures to
* generate geometry aligned from the view directly in world space. */
/* World space view origin and normal are not affected by object symmetry when doing symmetry
- * passes, so there is no separate variables with the true_ prefix to store their original values
- * without symmetry modifications. */
+ * passes, so there is no separate variables with the `true_` prefix to store their original
+ * values without symmetry modifications. */
float world_space_view_origin[3];
float world_space_view_normal[3];
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index fe7029c7457..f21c900941b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1608,7 +1608,7 @@ void ED_sculpt_undosys_type(UndoType *ut)
ut->step_decode = sculpt_undosys_step_decode;
ut->step_free = sculpt_undosys_step_free;
- ut->flags = 0;
+ ut->flags = UNDOTYPE_FLAG_DECODE_ACTIVE_STEP;
ut->step_size = sizeof(SculptUndoStep);
}
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 9e69b0a72db..d69c7ab8d48 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -813,7 +813,7 @@ static int action_layer_next_exec(bContext *C, wmOperator *op)
NlaTrack *act_track;
Scene *scene = CTX_data_scene(C);
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = BKE_scene_ctime_get(scene);
/* Get active track */
act_track = BKE_nlatrack_find_tweaked(adt);
@@ -925,7 +925,7 @@ static int action_layer_prev_exec(bContext *C, wmOperator *op)
NlaTrack *nlt;
Scene *scene = CTX_data_scene(C);
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = BKE_scene_ctime_get(scene);
/* Sanity Check */
if (adt == NULL) {
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 4d568017b4f..faa4b3cc9cc 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -523,6 +523,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
char orgname[FILE_MAX + 12];
char filename[FILE_MAX + 12];
wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
ARegion *region = CTX_wm_region(C);
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
@@ -542,12 +543,16 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
else {
/* If rename is successful, scroll to newly renamed entry. */
BLI_strncpy(params->renamefile, filename, sizeof(params->renamefile));
- file_params_invoke_rename_postscroll(wm, CTX_wm_window(C), sfile);
+ file_params_invoke_rename_postscroll(wm, win, sfile);
}
/* to make sure we show what is on disk */
ED_fileselect_clear(wm, sfile);
}
+ else {
+ /* Renaming failed, reset the name for further renaming handling. */
+ BLI_strncpy(params->renamefile, oldname, sizeof(params->renamefile));
+ }
ED_region_tag_redraw(region);
}
@@ -812,6 +817,8 @@ static void draw_details_columns(const FileSelectParams *params,
void file_draw_list(const bContext *C, ARegion *region)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
FileLayout *layout = ED_fileselect_get_layout(sfile, region);
@@ -882,12 +889,12 @@ void file_draw_list(const bContext *C, ARegion *region)
// printf("%s: preview task: %d\n", __func__, previews_running);
if (previews_running && !sfile->previews_timer) {
sfile->previews_timer = WM_event_add_timer_notifier(
- CTX_wm_manager(C), CTX_wm_window(C), NC_SPACE | ND_SPACE_FILE_PREVIEW, 0.01);
+ wm, win, NC_SPACE | ND_SPACE_FILE_PREVIEW, 0.01);
}
if (!previews_running && sfile->previews_timer) {
/* Preview is not running, no need to keep generating update events! */
// printf("%s: Inactive preview task, sleeping!\n", __func__);
- WM_event_remove_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C), sfile->previews_timer);
+ WM_event_remove_timer_notifier(wm, win, sfile->previews_timer);
sfile->previews_timer = NULL;
}
}
@@ -998,8 +1005,19 @@ void file_draw_list(const bContext *C, ARegion *region)
UI_but_flag_enable(but, UI_BUT_NO_UTF8); /* allow non utf8 names */
UI_but_flag_disable(but, UI_BUT_UNDO);
if (false == UI_but_active_only(C, region, block, but)) {
- file_selflag = filelist_entry_select_set(
- sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL);
+ /* Note that this is the only place where we can also handle a cancelled renaming. */
+
+ file_params_rename_end(wm, win, sfile, file);
+
+ /* After the rename button is removed, we need to make sure the view is redrawn once more,
+ * in case selection changed. Usually UI code would trigger that redraw, but the rename
+ * operator may have been called from a different region.
+ * Tagging regions for redrawing while drawing is rightfully prevented. However, this
+ * active button removing basically introduces handling logic to drawing code. So a
+ * notifier should be an acceptable workaround. */
+ WM_event_add_notifier_ex(wm, win, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
+ file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL);
}
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index b2182c45f2a..0bbed65671c 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -109,6 +109,7 @@ FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
float file_string_width(const char *str);
float file_font_pointsize(void);
+void file_select_deselect_all(SpaceFile *sfile, uint flag);
int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matched_file);
int autocomplete_directory(struct bContext *C, char *str, void *arg_v);
int autocomplete_file(struct bContext *C, char *str, void *arg_v);
@@ -120,6 +121,10 @@ void file_params_renamefile_clear(struct FileSelectParams *params);
void file_params_invoke_rename_postscroll(struct wmWindowManager *wm,
struct wmWindow *win,
SpaceFile *sfile);
+void file_params_rename_end(struct wmWindowManager *wm,
+ struct wmWindow *win,
+ SpaceFile *sfile,
+ struct FileDirEntry *rename_file);
void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params);
typedef void *onReloadFnData;
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 612f3a67aa3..995383d9d0e 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -104,15 +104,6 @@ static FileSelection find_file_mouse_rect(SpaceFile *sfile,
return sel;
}
-static void file_deselect_all(SpaceFile *sfile, uint flag)
-{
- FileSelection sel;
- sel.first = 0;
- sel.last = filelist_files_ensure(sfile->files) - 1;
-
- filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
-}
-
typedef enum FileSelect {
FILE_SELECT_NOTHING = 0,
FILE_SELECT_DIR = 1,
@@ -239,7 +230,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
}
/**
- * \warning: loops over all files so better use cautiously
+ * \warning Loops over all files so better use cautiously.
*/
static bool file_is_any_selected(struct FileList *files)
{
@@ -444,7 +435,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve
if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
int idx;
- file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
+ file_select_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
filelist_entries_select_index_range_set(
sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
@@ -472,7 +463,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve
params->highlight_file = -1;
params->sel_first = params->sel_last = -1;
fileselect_file_set(sfile, params->active_file);
- file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
+ file_select_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
@@ -491,7 +482,7 @@ static int file_box_select_exec(bContext *C, wmOperator *op)
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- file_deselect_all(sfile, FILE_SEL_SELECTED);
+ file_select_deselect_all(sfile, FILE_SEL_SELECTED);
}
ED_fileselect_layout_isect_rect(sfile->layout, &region->v2d, &rect, &rect);
@@ -573,7 +564,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if ((idx >= 0) && (idx < numfiles)) {
/* single select, deselect all selected first */
if (!extend) {
- file_deselect_all(sfile, FILE_SEL_SELECTED);
+ file_select_deselect_all(sfile, FILE_SEL_SELECTED);
}
}
}
@@ -588,7 +579,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (ret == FILE_SELECT_NOTHING) {
if (deselect_all) {
- file_deselect_all(sfile, FILE_SEL_SELECTED);
+ file_select_deselect_all(sfile, FILE_SEL_SELECTED);
}
}
else if (ret == FILE_SELECT_DIR) {
@@ -721,7 +712,7 @@ static bool file_walk_select_selection_set(wmWindow *win,
}
else {
/* deselect all first */
- file_deselect_all(sfile, FILE_SEL_SELECTED);
+ file_select_deselect_all(sfile, FILE_SEL_SELECTED);
/* highlight file under mouse pos */
params->highlight_file = -1;
@@ -2349,6 +2340,7 @@ static int file_directory_new_exec(bContext *C, wmOperator *op)
/* If we don't enter the directory directly, remember file to jump into editing. */
if (do_diropen == false) {
+ BLI_assert(params->rename_id == NULL || !"File rename handling should immediately clear rename_id when done, because otherwise it will keep taking precedence over renamefile.");
BLI_strncpy(params->renamefile, name, FILE_MAXFILE);
rename_flag = FILE_PARAMS_RENAME_PENDING;
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index ecd21907ed1..0e15538e03b 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -2016,19 +2016,21 @@ FileDirEntry *filelist_file(struct FileList *filelist, int index)
return filelist_file_ex(filelist, index, true);
}
-int filelist_file_findpath(struct FileList *filelist, const char *filename)
+/**
+ * Find a file from a file name, or more precisely, its file-list relative path, inside the
+ * filtered items. \return The index of the found file or -1.
+ */
+int filelist_file_find_path(struct FileList *filelist, const char *filename)
{
- int fidx = -1;
-
if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
- return fidx;
+ return -1;
}
/* XXX TODO: Cache could probably use a ghash on paths too? Not really urgent though.
* This is only used to find again renamed entry,
* annoying but looks hairy to get rid of it currently. */
- for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
+ for (int fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
if (STREQ(entry->relpath, filename)) {
return fidx;
@@ -2039,6 +2041,26 @@ int filelist_file_findpath(struct FileList *filelist, const char *filename)
}
/**
+ * Find a file representing \a id.
+ * \return The index of the found file or -1.
+ */
+int filelist_file_find_id(const FileList *filelist, const ID *id)
+{
+ if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
+ return -1;
+ }
+
+ for (int fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
+ FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
+ if (entry->local_data.id == id) {
+ return fidx;
+ }
+ }
+
+ return -1;
+}
+
+/**
* Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET.
*/
ID *filelist_file_get_id(const FileDirEntry *file)
@@ -2068,9 +2090,6 @@ void filelist_uid_unset(FileUID *r_uid)
*r_uid = FILE_UID_UNSET;
}
-/**
- * \warning: The UID will only be valid for the current session. Use as runtime data only!
- */
void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size)
{
/* Always keep it power of 2, in [256, 8192] range for now,
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index e6c4b8e1a07..0aace74e621 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -97,7 +97,8 @@ int filelist_needs_reading(struct FileList *filelist);
FileDirEntry *filelist_file(struct FileList *filelist, int index);
FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request);
-int filelist_file_findpath(struct FileList *filelist, const char *file);
+int filelist_file_find_path(struct FileList *filelist, const char *file);
+int filelist_file_find_id(const struct FileList *filelist, const struct ID *id);
struct ID *filelist_file_get_id(const struct FileDirEntry *file);
bool filelist_uid_is_set(const FileUID uid);
void filelist_uid_unset(FileUID *r_uid);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 4e59e4ba06e..b7accbf71e5 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -1086,6 +1086,15 @@ void ED_file_change_dir(bContext *C)
ED_file_change_dir_ex(C, area);
}
+void file_select_deselect_all(SpaceFile *sfile, uint flag)
+{
+ FileSelection sel;
+ sel.first = 0;
+ sel.last = filelist_files_ensure(sfile->files) - 1;
+
+ filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
+}
+
int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matched_file)
{
int match = 0;
@@ -1237,7 +1246,7 @@ void file_params_smoothscroll_timer_clear(wmWindowManager *wm, wmWindow *win, Sp
* Set the renaming-state to #FILE_PARAMS_RENAME_POSTSCROLL_PENDING and trigger the smooth-scroll
* timer. To be used right after a file was renamed.
* Note that the caller is responsible for setting the correct rename-file info
- * (#FileSelectParams.renamefile or #FileSelectParams.renamefile_uuid).
+ * (#FileSelectParams.renamefile or #FileSelectParams.rename_id).
*/
void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
{
@@ -1252,12 +1261,40 @@ void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, Sp
sfile->scroll_offset = 0;
}
+/**
+ * To be executed whenever renaming ends (successfully or not).
+ */
+void file_params_rename_end(wmWindowManager *wm,
+ wmWindow *win,
+ SpaceFile *sfile,
+ FileDirEntry *rename_file)
+{
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+
+ filelist_entry_select_set(
+ sfile->files, rename_file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL);
+
+ /* Ensure smooth-scroll timer is active, even if not needed, because that way rename state is
+ * handled properly. */
+ file_params_invoke_rename_postscroll(wm, win, sfile);
+ /* Also always activate the rename file, even if renaming was cancelled. */
+ file_params_renamefile_activate(sfile, params);
+}
+
void file_params_renamefile_clear(FileSelectParams *params)
{
params->renamefile[0] = '\0';
+ params->rename_id = NULL;
params->rename_flag = 0;
}
+static int file_params_find_renamed(const FileSelectParams *params, struct FileList *filelist)
+{
+ /* Find the file either through the local ID/asset it represents or its relative path. */
+ return (params->rename_id != NULL) ? filelist_file_find_id(filelist, params->rename_id) :
+ filelist_file_find_path(filelist, params->renamefile);
+}
+
/**
* Helper used by both main update code, and smooth-scroll timer,
* to try to enable rename editing from #FileSelectParams.renamefile name.
@@ -1271,20 +1308,26 @@ void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
return;
}
- BLI_assert(params->renamefile[0] != '\0');
+ BLI_assert(params->renamefile[0] != '\0' || params->rename_id != NULL);
- const int idx = filelist_file_findpath(sfile->files, params->renamefile);
+ const int idx = file_params_find_renamed(params, sfile->files);
if (idx >= 0) {
FileDirEntry *file = filelist_file(sfile->files, idx);
BLI_assert(file != NULL);
+ params->active_file = idx;
+ filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+
if ((params->rename_flag & FILE_PARAMS_RENAME_PENDING) != 0) {
filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
}
else if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_PENDING) != 0) {
- filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
- params->renamefile[0] = '\0';
+ file_select_deselect_all(sfile, FILE_SEL_SELECTED);
+ filelist_entry_select_set(
+ sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED | FILE_SEL_HIGHLIGHTED, CHECK_ALL);
+ params->active_file = idx;
+ file_params_renamefile_clear(params);
params->rename_flag = FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE;
}
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 64b43ac74a5..05d484d8e2e 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -32,6 +32,7 @@
#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -469,10 +470,19 @@ static void file_listener(const wmSpaceTypeListenerParams *listener_params)
break;
case NC_ID: {
switch (wmn->action) {
- case NA_RENAME:
+ case NA_RENAME: {
+ const ID *active_file_id = ED_fileselect_active_asset_get(sfile);
+ /* If a renamed ID is active in the file browser, update scrolling to keep it in view. */
+ if (active_file_id && (wmn->reference == active_file_id)) {
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ params->rename_id = active_file_id;
+ file_params_invoke_rename_postscroll(G_MAIN->wm.first, listener_params->window, sfile);
+ }
+
/* Force list to update sorting (with a full reset for now). */
file_reset_filelist_showing_main_data(area, sfile);
break;
+ }
}
break;
}
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index 082f66b57af..cc6effd0f71 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -1006,7 +1006,7 @@ void ED_image_undosys_type(UndoType *ut)
* specific case, see `image_undosys_step_encode` code. We cannot specify
* `UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE` though, as it can be called with a NULL context by
* current code. */
- ut->flags = 0;
+ ut->flags = UNDOTYPE_FLAG_DECODE_ACTIVE_STEP;
ut->step_size = sizeof(ImageUndoStep);
}
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index aaf9852e212..94e53958524 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -564,12 +564,11 @@ void FILE_OT_find_missing_files(wmOperatorType *ot)
/** \name Report Box Operator
* \{ */
-/* Hard to decide whether to keep this as an operator,
- * or turn it into a hardcoded ui control feature,
- * handling TIMER events for all regions in interface_handlers.c
+/* NOTE(matt): Hard to decide whether to keep this as an operator,
+ * or turn it into a hard_coded UI control feature,
+ * handling TIMER events for all regions in `interface_handlers.c`.
* Not sure how good that is to be accessing UI data from
- * inactive regions, so use this for now. --matt
- */
+ * inactive regions, so use this for now. */
#define INFO_TIMEOUT 5.0f
#define ERROR_TIMEOUT 10.0f
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index f2cea23af76..0498964c549 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -288,14 +288,14 @@ static int mouse_nla_channels(
/* button region... */
if (x >= (v2d->cur.xmax - NLACHANNEL_BUTTON_WIDTH)) {
if (nlaedit_is_tweakmode_on(ac) == 0) {
- /* 'push-down' action - only usable when not in TweakMode */
+ /* 'push-down' action - only usable when not in tweak-mode */
/* TODO: make this use the operator instead of calling the function directly
* however, calling the operator requires that we supply the args,
* and that works with proper buttons only */
BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(ale->id));
}
else {
- /* when in tweakmode, this button becomes the toggle for mapped editing */
+ /* When in tweak-mode, this button becomes the toggle for mapped editing. */
adt->flag ^= ADT_NLA_EDIT_NOMAP;
}
@@ -308,13 +308,13 @@ static int mouse_nla_channels(
/* NOTE: rest of NLA-Action name doubles for operating on the AnimData block
* - this is useful when there's no clear divider, and makes more sense in
* the case of users trying to use this to change actions
- * - in tweakmode, clicking here gets us out of tweakmode, as changing selection
- * while in tweakmode is really evil!
+ * - in tweak-mode, clicking here gets us out of tweak-mode, as changing selection
+ * while in tweak-mode is really evil!
* - we disable "solo" flags too, to make it easier to work with stashed actions
* with less trouble
*/
if (nlaedit_is_tweakmode_on(ac)) {
- /* exit tweakmode immediately */
+ /* Exit tweak-mode immediately. */
nlaedit_disable_tweakmode(ac, true);
/* changes to NLA-Action occurred */
@@ -515,7 +515,7 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* 'push-down' action - only usable when not in TweakMode */
+ /* 'push-down' action - only usable when not in Tweak-mode. */
BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(id));
struct Main *bmain = CTX_data_main(C);
@@ -874,7 +874,7 @@ static int nlaedit_objects_add_exec(bContext *C, wmOperator *UNUSED(op))
/* operate on selected objects... */
CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
/* ensure that object has AnimData... that's all */
- BKE_animdata_add_id(&ob->id);
+ BKE_animdata_ensure_id(&ob->id);
}
CTX_DATA_END;
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index ae86efc0e6a..56efcd8571f 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -135,7 +135,7 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ale->data;
- /* try entering tweakmode if valid */
+ /* Try entering tweak-mode if valid. */
ok |= BKE_nla_tweakmode_enter(adt);
/* mark the active track as being "solo"? */
@@ -154,9 +154,8 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
- /* if we managed to enter tweakmode on at least one AnimData block,
- * set the flag for this in the active scene and send notifiers
- */
+ /* If we managed to enter tweak-mode on at least one AnimData block,
+ * set the flag for this in the active scene and send notifiers. */
if (ac.scene && ok) {
/* set editing flag */
ac.scene->flag |= SCE_NLA_EDIT_ON;
@@ -206,7 +205,7 @@ void NLA_OT_tweakmode_enter(wmOperatorType *ot)
/** \name Disable Tweak-Mode Operator
* \{ */
-/* NLA Editor internal API function for exiting tweakmode */
+/* NLA Editor internal API function for exiting tweak-mode. */
bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
{
ListBase anim_data = {NULL, NULL};
@@ -232,7 +231,7 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
BKE_nlatrack_solo_toggle(adt, NULL);
}
- /* to be sure that we're doing everything right, just exit tweakmode... */
+ /* To be sure that we're doing everything right, just exit tweak-mode. */
BKE_nla_tweakmode_exit(adt);
ale->update |= ANIM_UPDATE_DEPS;
@@ -242,7 +241,7 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
- /* if we managed to enter tweakmode on at least one AnimData block,
+ /* if we managed to enter tweak-mode on at least one AnimData block,
* set the flag for this in the active scene and send notifiers
*/
if (ac->scene) {
@@ -257,7 +256,7 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
return true;
}
-/* exit tweakmode operator callback */
+/* Exit tweak-mode operator callback. */
static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 631dc2e550c..28f194877fa 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -39,17 +39,16 @@
/* ************************** poll callbacks for operators **********************************/
-/* tweakmode is NOT enabled */
+/* Tweak-mode is NOT enabled. */
bool nlaop_poll_tweakmode_off(bContext *C)
{
Scene *scene;
/* for now, we check 2 things:
* 1) active editor must be NLA
- * 2) tweakmode is currently set as a 'per-scene' flag
+ * 2) tweak-mode is currently set as a 'per-scene' flag
* so that it will affect entire NLA data-sets,
- * but not all AnimData blocks will be in tweakmode for
- * various reasons
+ * but not all AnimData blocks will be in tweak-mode for various reasons.
*/
if (ED_operator_nla_active(C) == 0) {
return 0;
@@ -63,17 +62,16 @@ bool nlaop_poll_tweakmode_off(bContext *C)
return 1;
}
-/* tweakmode IS enabled */
+/* Tweak-mode IS enabled. */
bool nlaop_poll_tweakmode_on(bContext *C)
{
Scene *scene;
/* for now, we check 2 things:
* 1) active editor must be NLA
- * 2) tweakmode is currently set as a 'per-scene' flag
+ * 2) tweak-mode is currently set as a 'per-scene' flag
* so that it will affect entire NLA data-sets,
- * but not all AnimData blocks will be in tweakmode for
- * various reasons
+ * but not all AnimData blocks will be in tweak-mode for various reasons.
*/
if (ED_operator_nla_active(C) == 0) {
return 0;
@@ -87,7 +85,7 @@ bool nlaop_poll_tweakmode_on(bContext *C)
return 1;
}
-/* is tweakmode enabled - for use in NLA operator code */
+/* is tweak-mode enabled - for use in NLA operator code */
bool nlaedit_is_tweakmode_on(bAnimContext *ac)
{
if (ac && ac->scene) {
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
index dc95a01a021..246c3e0156a 100644
--- a/source/blender/editors/space_nla/nla_select.c
+++ b/source/blender/editors/space_nla/nla_select.c
@@ -453,7 +453,7 @@ static void nlaedit_select_leftright(bContext *C,
Scene *scene = ac->scene;
float xmin, xmax;
- /* if currently in tweakmode, exit tweakmode first */
+ /* if currently in tweak-mode, exit tweak-mode first */
if (scene->flag & SCE_NLA_EDIT_ON) {
WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, NULL);
}
@@ -612,7 +612,7 @@ static int mouse_nla_strips(bContext *C,
nlaedit_strip_at_region_position(ac, mval[0], mval[1], &ale, &strip);
- /* if currently in tweakmode, exit tweakmode before changing selection states
+ /* if currently in tweak-mode, exit tweak-mode before changing selection states
* now that we've found our target...
*/
if (scene->flag & SCE_NLA_EDIT_ON) {
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index 6e234c5b2ce..80d3b43bf6b 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../compositor
../../depsgraph
../../draw
+ ../../functions
../../gpu
../../imbuf
../../makesdna
@@ -39,7 +40,6 @@ set(INC
set(SRC
drawnode.cc
node_add.cc
- node_buttons.c
node_draw.cc
node_edit.cc
node_geometry_attribute_search.cc
@@ -78,4 +78,20 @@ if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
+if(WITH_TBB)
+ add_definitions(-DWITH_TBB)
+ if(WIN32)
+ # TBB includes Windows.h which will define min/max macros
+ # that will collide with the stl versions.
+ add_definitions(-DNOMINMAX)
+ endif()
+ list(APPEND INC_SYS
+ ${TBB_INCLUDE_DIRS}
+ )
+
+ list(APPEND LIB
+ ${TBB_LIBRARIES}
+ )
+endif()
+
blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
deleted file mode 100644
index 336b0c46a81..00000000000
--- a/source/blender/editors/space_node/node_buttons.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup spnode
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_node_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
-#include "BLT_translation.h"
-
-#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_node.h"
-#include "BKE_screen.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "RNA_access.h"
-
-#include "ED_screen.h"
-
-#include "UI_resources.h"
-
-#include "node_intern.h" /* own include */
-
-/* ******************* node space & buttons ************** */
-
-#if 0
-/* poll for active nodetree */
-static bool active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
-
- return (snode && snode->nodetree);
-}
-#endif
-
-static bool node_sockets_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
-
- return (snode && snode->nodetree && G.debug_value == 777);
-}
-
-static void node_sockets_panel(const bContext *C, Panel *panel)
-{
- SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */
- bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */
- bNode *node = nodeGetActive(ntree);
- if (node == NULL) {
- return;
- }
-
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- char name[UI_MAX_NAME_STR];
- BLI_snprintf(name, sizeof(name), "%s:", socket->name);
-
- uiLayout *split = uiLayoutSplit(panel->layout, 0.35f, false);
- uiItemL(split, name, ICON_NONE);
- uiTemplateNodeLink(split, (bContext *)C, ntree, node, socket);
- }
-}
-
-static bool node_tree_interface_poll(const bContext *C, PanelType *UNUSED(pt))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
-
- return (snode && snode->edittree &&
- (snode->edittree->inputs.first || snode->edittree->outputs.first));
-}
-
-static bNodeSocket *node_tree_find_active_socket(bNodeTree *ntree, const eNodeSocketInOut in_out)
-{
- ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs;
- LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
- if (socket->flag & SELECT) {
- return socket;
- }
- }
- return NULL;
-}
-
-static void draw_socket_list(const bContext *C,
- uiLayout *layout,
- bNodeTree *ntree,
- const eNodeSocketInOut in_out)
-{
- PointerRNA tree_ptr;
- RNA_id_pointer_create((ID *)ntree, &tree_ptr);
-
- uiLayout *split = uiLayoutRow(layout, false);
- uiLayout *list_col = uiLayoutColumn(split, true);
- uiTemplateList(list_col,
- (bContext *)C,
- "NODE_UL_interface_sockets",
- (in_out == SOCK_IN) ? "inputs" : "outputs",
- &tree_ptr,
- (in_out == SOCK_IN) ? "inputs" : "outputs",
- &tree_ptr,
- (in_out == SOCK_IN) ? "active_input" : "active_output",
- NULL,
- 0,
- 0,
- 0,
- 0,
- false,
- false);
- PointerRNA opptr;
- uiLayout *ops_col = uiLayoutColumn(split, false);
- uiLayout *add_remove_col = uiLayoutColumn(ops_col, true);
- wmOperatorType *ot = WM_operatortype_find("NODE_OT_tree_socket_add", false);
- uiItemFullO_ptr(add_remove_col, ot, "", ICON_ADD, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "in_out", in_out);
- ot = WM_operatortype_find("NODE_OT_tree_socket_remove", false);
- uiItemFullO_ptr(add_remove_col, ot, "", ICON_REMOVE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "in_out", in_out);
-
- uiItemS(ops_col);
-
- uiLayout *up_down_col = uiLayoutColumn(ops_col, true);
- ot = WM_operatortype_find("NODE_OT_tree_socket_move", false);
- uiItemFullO_ptr(up_down_col, ot, "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "direction", 1);
- RNA_enum_set(&opptr, "in_out", in_out);
- uiItemFullO_ptr(up_down_col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
- RNA_enum_set(&opptr, "direction", 2);
- RNA_enum_set(&opptr, "in_out", in_out);
-
- bNodeSocket *socket = node_tree_find_active_socket(ntree, in_out);
- if (socket != NULL) {
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- PointerRNA socket_ptr;
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, socket, &socket_ptr);
- uiItemR(layout, &socket_ptr, "name", 0, NULL, ICON_NONE);
-
- /* Display descriptions only for Geometry Nodes, since it's only used in the modifier panel. */
- if (ntree->type == NTREE_GEOMETRY) {
- uiItemR(layout, &socket_ptr, "description", 0, NULL, ICON_NONE);
- }
-
- if (socket->typeinfo->interface_draw) {
- socket->typeinfo->interface_draw((bContext *)C, layout, &socket_ptr);
- }
- }
-}
-
-static void node_tree_interface_inputs_panel(const bContext *C, Panel *panel)
-{
- SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */
- bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */
-
- draw_socket_list(C, panel->layout, ntree, SOCK_IN);
-}
-
-static void node_tree_interface_outputs_panel(const bContext *C, Panel *panel)
-{
- SpaceNode *snode = CTX_wm_space_node(C); /* NULL checked in poll function. */
- bNodeTree *ntree = snode->edittree; /* NULL checked in poll function. */
-
- draw_socket_list(C, panel->layout, ntree, SOCK_OUT);
-}
-
-/* ******************* node buttons registration ************** */
-
-void node_buttons_register(ARegionType *art)
-{
- {
- PanelType *pt = MEM_callocN(sizeof(PanelType), __func__);
- strcpy(pt->idname, "NODE_PT_sockets");
- strcpy(pt->category, N_("Node"));
- strcpy(pt->label, N_("Sockets"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = node_sockets_panel;
- pt->poll = node_sockets_poll;
- pt->flag |= PANEL_TYPE_DEFAULT_CLOSED;
- BLI_addtail(&art->paneltypes, pt);
- }
-
- {
- PanelType *pt = MEM_callocN(sizeof(PanelType), __func__);
- strcpy(pt->idname, "NODE_PT_node_tree_interface_inputs");
- strcpy(pt->category, N_("Group"));
- strcpy(pt->label, N_("Inputs"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = node_tree_interface_inputs_panel;
- pt->poll = node_tree_interface_poll;
- BLI_addtail(&art->paneltypes, pt);
- }
- {
- PanelType *pt = MEM_callocN(sizeof(PanelType), __func__);
- strcpy(pt->idname, "NODE_PT_node_tree_interface_outputs");
- strcpy(pt->category, N_("Group"));
- strcpy(pt->label, N_("Outputs"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = node_tree_interface_outputs_panel;
- pt->poll = node_tree_interface_poll;
- BLI_addtail(&art->paneltypes, pt);
- }
-}
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 8a341da0b5c..d4f178603b8 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -48,7 +48,6 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
-#include "BKE_node_ui_storage.hh"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -76,6 +75,8 @@
#include "RNA_access.h"
+#include "NOD_geometry_nodes_eval_log.hh"
+
#include "node_intern.h" /* own include */
#ifdef WITH_COMPOSITOR
@@ -86,6 +87,9 @@ using blender::Map;
using blender::Set;
using blender::Span;
using blender::Vector;
+using blender::fn::CPPType;
+using blender::fn::GPointer;
+namespace geo_log = blender::nodes::geometry_nodes_eval_log;
extern "C" {
/* XXX interface.h */
@@ -1185,14 +1189,14 @@ void node_draw_sockets(const View2D *v2d,
}
}
-static int node_error_type_to_icon(const NodeWarningType type)
+static int node_error_type_to_icon(const geo_log::NodeWarningType type)
{
switch (type) {
- case NodeWarningType::Error:
+ case geo_log::NodeWarningType::Error:
return ICON_ERROR;
- case NodeWarningType::Warning:
+ case geo_log::NodeWarningType::Warning:
return ICON_ERROR;
- case NodeWarningType::Info:
+ case geo_log::NodeWarningType::Info:
return ICON_INFO;
}
@@ -1200,14 +1204,14 @@ static int node_error_type_to_icon(const NodeWarningType type)
return ICON_ERROR;
}
-static uint8_t node_error_type_priority(const NodeWarningType type)
+static uint8_t node_error_type_priority(const geo_log::NodeWarningType type)
{
switch (type) {
- case NodeWarningType::Error:
+ case geo_log::NodeWarningType::Error:
return 3;
- case NodeWarningType::Warning:
+ case geo_log::NodeWarningType::Warning:
return 2;
- case NodeWarningType::Info:
+ case geo_log::NodeWarningType::Info:
return 1;
}
@@ -1215,11 +1219,11 @@ static uint8_t node_error_type_priority(const NodeWarningType type)
return 0;
}
-static NodeWarningType node_error_highest_priority(Span<NodeWarning> warnings)
+static geo_log::NodeWarningType node_error_highest_priority(Span<geo_log::NodeWarning> warnings)
{
uint8_t highest_priority = 0;
- NodeWarningType highest_priority_type = NodeWarningType::Info;
- for (const NodeWarning &warning : warnings) {
+ geo_log::NodeWarningType highest_priority_type = geo_log::NodeWarningType::Info;
+ for (const geo_log::NodeWarning &warning : warnings) {
const uint8_t priority = node_error_type_priority(warning.type);
if (priority > highest_priority) {
highest_priority = priority;
@@ -1229,15 +1233,17 @@ static NodeWarningType node_error_highest_priority(Span<NodeWarning> warnings)
return highest_priority_type;
}
+struct NodeErrorsTooltipData {
+ Span<geo_log::NodeWarning> warnings;
+};
+
static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
{
- const NodeUIStorage **storage_pointer_alloc = static_cast<const NodeUIStorage **>(argN);
- const NodeUIStorage *node_ui_storage = *storage_pointer_alloc;
- Span<NodeWarning> warnings = node_ui_storage->warnings;
+ NodeErrorsTooltipData &data = *(NodeErrorsTooltipData *)argN;
std::string complete_string;
- for (const NodeWarning &warning : warnings.drop_back(1)) {
+ for (const geo_log::NodeWarning &warning : data.warnings.drop_back(1)) {
complete_string += warning.message;
/* Adding the period is not ideal for multi-line messages, but it is consistent
* with other tooltip implementations in Blender, so it is added here. */
@@ -1246,7 +1252,7 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char
}
/* Let the tooltip system automatically add the last period. */
- complete_string += warnings.last().message;
+ complete_string += data.warnings.last().message;
return BLI_strdupn(complete_string.c_str(), complete_string.size());
}
@@ -1254,20 +1260,26 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char
#define NODE_HEADER_ICON_SIZE (0.8f * U.widget_unit)
static void node_add_error_message_button(
- const bContext *C, bNodeTree &ntree, bNode &node, const rctf &rect, float &icon_offset)
+ const bContext *C, bNodeTree &UNUSED(ntree), bNode &node, const rctf &rect, float &icon_offset)
{
- const NodeUIStorage *node_ui_storage = BKE_node_tree_ui_storage_get_from_context(C, ntree, node);
- if (node_ui_storage == nullptr || node_ui_storage->warnings.is_empty()) {
+ SpaceNode *snode = CTX_wm_space_node(C);
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(*snode,
+ node);
+ if (node_log == nullptr) {
+ return;
+ }
+
+ Span<geo_log::NodeWarning> warnings = node_log->warnings();
+
+ if (warnings.is_empty()) {
return;
}
- /* The UI API forces us to allocate memory for each error button, because the
- * ownership of #UI_but_func_tooltip_set's argument is transferred to the button. */
- const NodeUIStorage **storage_pointer_alloc = (const NodeUIStorage **)MEM_mallocN(
- sizeof(NodeUIStorage *), __func__);
- *storage_pointer_alloc = node_ui_storage;
+ NodeErrorsTooltipData *tooltip_data = (NodeErrorsTooltipData *)MEM_mallocN(
+ sizeof(NodeErrorsTooltipData), __func__);
+ tooltip_data->warnings = warnings;
- const NodeWarningType display_type = node_error_highest_priority(node_ui_storage->warnings);
+ const geo_log::NodeWarningType display_type = node_error_highest_priority(warnings);
icon_offset -= NODE_HEADER_ICON_SIZE;
UI_block_emboss_set(node.block, UI_EMBOSS_NONE);
@@ -1285,7 +1297,7 @@ static void node_add_error_message_button(
0,
0,
nullptr);
- UI_but_func_tooltip_set(but, node_errors_tooltip_fn, storage_pointer_alloc, MEM_freeN);
+ UI_but_func_tooltip_set(but, node_errors_tooltip_fn, tooltip_data, MEM_freeN);
UI_block_emboss_set(node.block, UI_EMBOSS);
}
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 9a6603eb589..5dd935bdd76 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -2414,6 +2414,109 @@ void NODE_OT_tree_socket_remove(wmOperatorType *ot)
RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Type", "");
}
+/********************** Change interface socket type operator *********************/
+
+static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNodeTree *ntree = snode->edittree;
+ const eNodeSocketInOut in_out = (eNodeSocketInOut)RNA_enum_get(op->ptr, "in_out");
+ const bNodeSocketType *socket_type = rna_node_socket_type_from_enum(
+ RNA_enum_get(op->ptr, "socket_type"));
+ ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs;
+
+ Main *main = CTX_data_main(C);
+
+ bNodeSocket *iosock = ntree_get_active_interface_socket(sockets);
+ if (iosock == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* The type remains the same, so we don't need to change anything. */
+ if (iosock->typeinfo == socket_type) {
+ return OPERATOR_FINISHED;
+ }
+
+ /* Don't handle subtypes for now. */
+ nodeModifySocketType(ntree, nullptr, iosock, socket_type->idname);
+
+ /* Need the extra update here because the loop above does not check for valid links in the node
+ * group we're currently editing. */
+ ntree->update |= NTREE_UPDATE_GROUP | NTREE_UPDATE_LINKS;
+
+ /* Deactivate sockets. */
+ LISTBASE_FOREACH (bNodeSocket *, socket_iter, sockets) {
+ socket_iter->flag &= ~SELECT;
+ }
+ /* Make the new socket active. */
+ iosock->flag |= SELECT;
+
+ ntreeUpdateTree(main, ntree);
+
+ snode_notify(C, snode);
+ snode_dag_update(C, snode);
+
+ WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool socket_change_poll_type(void *userdata, bNodeSocketType *socket_type)
+{
+ /* Check if the node tree supports the socket type. */
+ bNodeTreeType *ntreetype = (bNodeTreeType *)userdata;
+ if (ntreetype->valid_socket_type && !ntreetype->valid_socket_type(ntreetype, socket_type)) {
+ return false;
+ }
+
+ /* Only use basic socket types for this enum. */
+ if (socket_type->subtype != PROP_NONE) {
+ return false;
+ }
+
+ return true;
+}
+
+static const EnumPropertyItem *socket_change_type_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ if (!C) {
+ return DummyRNA_NULL_items;
+ }
+
+ SpaceNode *snode = CTX_wm_space_node(C);
+ if (!snode || !snode->edittree) {
+ return DummyRNA_NULL_items;
+ }
+
+ return rna_node_socket_type_itemf(snode->edittree->typeinfo, socket_change_poll_type, r_free);
+}
+
+void NODE_OT_tree_socket_change_type(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Change Node Tree Interface Socket Type";
+ ot->description = "Change the type of a socket of the current node tree";
+ ot->idname = "NODE_OT_tree_socket_change_type";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = ntree_socket_change_type_exec;
+ ot->poll = ED_operator_node_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Type", "");
+ prop = RNA_def_enum(ot->srna, "socket_type", DummyRNA_DEFAULT_items, 0, "Socket Type", "");
+ RNA_def_enum_funcs(prop, socket_change_type_itemf);
+ ot->prop = prop;
+}
+
/********************** Move interface socket operator *********************/
static const EnumPropertyItem move_direction_items[] = {
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index 94080a7b616..a6901c21862 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -27,7 +27,6 @@
#include "DNA_space_types.h"
#include "BKE_context.h"
-#include "BKE_node_ui_storage.hh"
#include "BKE_object.h"
#include "RNA_access.h"
@@ -40,17 +39,21 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_geometry_nodes_eval_log.hh"
+
#include "node_intern.h"
using blender::IndexRange;
using blender::Map;
using blender::Set;
using blender::StringRef;
+namespace geo_log = blender::nodes::geometry_nodes_eval_log;
+using geo_log::GeometryAttributeInfo;
struct AttributeSearchData {
- AvailableAttributeInfo &dummy_info_for_search;
- const NodeUIStorage &ui_storage;
- bNodeSocket &socket;
+ const bNodeTree *tree;
+ const bNode *node;
+ bNodeSocket *socket;
};
/* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
@@ -73,7 +76,7 @@ static StringRef attribute_domain_string(const AttributeDomain domain)
/* Unicode arrow. */
#define MENU_SEP "\xe2\x96\xb6"
-static bool attribute_search_item_add(uiSearchItems *items, const AvailableAttributeInfo &item)
+static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttributeInfo &item)
{
const StringRef data_type_name = attribute_data_type_string(item.data_type);
const StringRef domain_name = attribute_domain_string(item.domain);
@@ -84,31 +87,47 @@ static bool attribute_search_item_add(uiSearchItems *items, const AvailableAttri
items, search_item_text.c_str(), (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0);
}
-static void attribute_search_update_fn(const bContext *UNUSED(C),
- void *arg,
- const char *str,
- uiSearchItems *items,
- const bool is_first)
+static GeometryAttributeInfo &get_dummy_item_info()
+{
+ static GeometryAttributeInfo info;
+ return info;
+}
+
+static void attribute_search_update_fn(
+ const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
{
AttributeSearchData *data = static_cast<AttributeSearchData *>(arg);
- const Set<AvailableAttributeInfo> &attribute_hints = data->ui_storage.attribute_hints;
+ SpaceNode *snode = CTX_wm_space_node(C);
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(
+ *snode, *data->node);
+ if (node_log == nullptr) {
+ return;
+ }
+ blender::Vector<const GeometryAttributeInfo *> infos = node_log->lookup_available_attributes();
+
+ GeometryAttributeInfo &dummy_info = get_dummy_item_info();
/* Any string may be valid, so add the current search string along with the hints. */
if (str[0] != '\0') {
- /* Note that the attribute domain and data type are dummies, since
- * #AvailableAttributeInfo equality is only based on the string. */
- if (!attribute_hints.contains(AvailableAttributeInfo{str, ATTR_DOMAIN_AUTO, CD_PROP_BOOL})) {
- data->dummy_info_for_search.name = std::string(str);
- UI_search_item_add(items, str, &data->dummy_info_for_search, ICON_ADD, 0, 0);
+ bool contained = false;
+ for (const GeometryAttributeInfo *attribute_info : infos) {
+ if (attribute_info->name == str) {
+ contained = true;
+ break;
+ }
+ }
+ if (!contained) {
+ dummy_info.name = str;
+ UI_search_item_add(items, str, &dummy_info, ICON_ADD, 0, 0);
}
}
if (str[0] == '\0' && !is_first) {
/* Allow clearing the text field when the string is empty, but not on the first pass,
* or opening an attribute field for the first time would show this search item. */
- data->dummy_info_for_search.name = std::string(str);
- UI_search_item_add(items, str, &data->dummy_info_for_search, ICON_X, 0, 0);
+ dummy_info.name = str;
+ UI_search_item_add(items, str, &dummy_info, ICON_X, 0, 0);
}
/* Don't filter when the menu is first opened, but still run the search
@@ -116,15 +135,15 @@ static void attribute_search_update_fn(const bContext *UNUSED(C),
const char *string = is_first ? "" : str;
StringSearch *search = BLI_string_search_new();
- for (const AvailableAttributeInfo &item : attribute_hints) {
- BLI_string_search_add(search, item.name.c_str(), (void *)&item);
+ for (const GeometryAttributeInfo *item : infos) {
+ BLI_string_search_add(search, item->name.c_str(), (void *)item);
}
- AvailableAttributeInfo **filtered_items;
+ GeometryAttributeInfo **filtered_items;
const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
for (const int i : IndexRange(filtered_amount)) {
- const AvailableAttributeInfo *item = filtered_items[i];
+ const GeometryAttributeInfo *item = filtered_items[i];
if (!attribute_search_item_add(items, *item)) {
break;
}
@@ -136,32 +155,25 @@ static void attribute_search_update_fn(const bContext *UNUSED(C),
static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
{
+ if (item_v == nullptr) {
+ return;
+ }
AttributeSearchData *data = static_cast<AttributeSearchData *>(data_v);
- AvailableAttributeInfo *item = static_cast<AvailableAttributeInfo *>(item_v);
+ GeometryAttributeInfo *item = (GeometryAttributeInfo *)item_v;
- bNodeSocket &socket = data->socket;
+ bNodeSocket &socket = *data->socket;
bNodeSocketValueString *value = static_cast<bNodeSocketValueString *>(socket.default_value);
BLI_strncpy(value->value, item->name.c_str(), MAX_NAME);
ED_undo_push(C, "Assign Attribute Name");
}
-void node_geometry_add_attribute_search_button(const bContext *C,
+void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
const bNodeTree *node_tree,
const bNode *node,
PointerRNA *socket_ptr,
uiLayout *layout)
{
- const NodeUIStorage *ui_storage = BKE_node_tree_ui_storage_get_from_context(
- C, *node_tree, *node);
-
- if (ui_storage == nullptr) {
- uiItemR(layout, socket_ptr, "default_value", 0, "", 0);
- return;
- }
-
- const NodeTreeUIStorage *tree_ui_storage = node_tree->ui_storage;
-
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but = uiDefIconTextButR(block,
UI_BTYPE_SEARCH_MENU,
@@ -181,10 +193,8 @@ void node_geometry_add_attribute_search_button(const bContext *C,
0.0f,
"");
- AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData,
- {tree_ui_storage->dummy_info_for_search,
- *ui_storage,
- *static_cast<bNodeSocket *>(socket_ptr->data)});
+ AttributeSearchData *data = OBJECT_GUARDED_NEW(
+ AttributeSearchData, {node_tree, node, (bNodeSocket *)socket_ptr->data});
UI_but_func_search_set_results_are_suggestions(but, true);
UI_but_func_search_set_sep_string(but, MENU_SEP);
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index e69f0cbea7f..09e5a110a45 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -140,9 +140,6 @@ void node_to_view(const struct bNode *node, float x, float y, float *rx, float *
void node_to_updated_rect(const struct bNode *node, rctf *r_rect);
void node_from_view(const struct bNode *node, float x, float y, float *rx, float *ry);
-/* node_buttons.c */
-void node_buttons_register(struct ARegionType *art);
-
/* node_toolbar.c */
void node_toolbar_register(struct ARegionType *art);
@@ -296,6 +293,7 @@ void NODE_OT_clipboard_paste(struct wmOperatorType *ot);
void NODE_OT_tree_socket_add(struct wmOperatorType *ot);
void NODE_OT_tree_socket_remove(struct wmOperatorType *ot);
+void NODE_OT_tree_socket_change_type(struct wmOperatorType *ot);
void NODE_OT_tree_socket_move(struct wmOperatorType *ot);
void NODE_OT_shader_script_update(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index ce65fe93f20..610c2889e7a 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -119,6 +119,7 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_tree_socket_add);
WM_operatortype_append(NODE_OT_tree_socket_remove);
+ WM_operatortype_append(NODE_OT_tree_socket_change_type);
WM_operatortype_append(NODE_OT_tree_socket_move);
WM_operatortype_append(NODE_OT_cryptomatte_layer_add);
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index d7e16dd69f1..ff848a7bb95 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -651,6 +651,10 @@ static void node_main_region_init(wmWindowManager *wm, ARegion *region)
lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
WM_event_add_dropbox_handler(&region->handlers, lb);
+
+ /* The backdrop image gizmo needs to change together with the view. So always refresh gizmos on
+ * region size changes. */
+ WM_gizmomap_tag_refresh(region->gizmo_map);
}
static void node_main_region_draw(const bContext *C, ARegion *region)
@@ -1094,8 +1098,6 @@ void ED_spacetype_node(void)
art->draw = node_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
- node_buttons_register(art);
-
/* regions: toolbar */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region");
art->regionid = RGN_TYPE_TOOLS;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index d1fb36979b4..db37c8c1c8c 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -2964,7 +2964,8 @@ static void outliner_draw_iconrow(bContext *C,
te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED);
/* object hierarchy always, further constrained on level */
- if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) {
+ if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) ||
+ ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL)) {
/* active blocks get white circle */
if (tselem->type == TSE_SOME_ID) {
if (te->idcode == ID_OB) {
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index f089a149805..96af8258010 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -86,7 +86,7 @@ class TreeDisplayViewLayer final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
private:
- void add_view_layer(ListBase &, TreeElement &);
+ void add_view_layer(Scene &, ListBase &, TreeElement *);
void add_layer_collections_recursive(ListBase &, ListBase &, TreeElement &);
void add_layer_collection_objects(ListBase &, LayerCollection &, TreeElement &);
void add_layer_collection_objects_children(TreeElement &);
diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
index 3059f8bfe0c..a17bf174a74 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
@@ -150,27 +150,25 @@ TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
}
/* Create data-block list parent element on demand. */
- if (id != nullptr) {
- TreeElement *ten;
+ TreeElement *ten;
- if (filter_id_type) {
- ten = tenlib;
- }
- else {
- ten = outliner_add_element(
- &space_outliner_, &tenlib->subtree, lbarray[a], nullptr, TSE_ID_BASE, 0);
- ten->directdata = lbarray[a];
- ten->name = outliner_idcode_to_plural(GS(id->name));
- }
+ if (filter_id_type) {
+ ten = tenlib;
+ }
+ else {
+ ten = outliner_add_element(
+ &space_outliner_, &tenlib->subtree, lbarray[a], nullptr, TSE_ID_BASE, 0);
+ ten->directdata = lbarray[a];
+ ten->name = outliner_idcode_to_plural(GS(id->name));
+ }
- for (ID *id : List<ID>(lbarray[a])) {
- if (override_library_id_filter_poll(lib, id)) {
- TreeElement *override_tree_element = outliner_add_element(
- &space_outliner_, &ten->subtree, id, ten, TSE_LIBRARY_OVERRIDE_BASE, 0);
+ for (ID *id : List<ID>(lbarray[a])) {
+ if (override_library_id_filter_poll(lib, id)) {
+ TreeElement *override_tree_element = outliner_add_element(
+ &space_outliner_, &ten->subtree, id, ten, TSE_LIBRARY_OVERRIDE_BASE, 0);
- if (BLI_listbase_is_empty(&override_tree_element->subtree)) {
- outliner_free_tree_element(override_tree_element, &ten->subtree);
- }
+ if (BLI_listbase_is_empty(&override_tree_element->subtree)) {
+ outliner_free_tree_element(override_tree_element, &ten->subtree);
}
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
index 402526bbe8d..c3d0aecd3cb 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
@@ -70,74 +70,69 @@ TreeDisplayViewLayer::TreeDisplayViewLayer(SpaceOutliner &space_outliner)
ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data)
{
ListBase tree = {nullptr};
-
Scene *scene = source_data.scene;
show_objects_ = !(space_outliner_.filter & SO_FILTER_NO_OBJECT);
- const bool show_children = (space_outliner_.filter & SO_FILTER_NO_CHILDREN) == 0;
-
for (auto *view_layer : ListBaseWrapper<ViewLayer>(scene->view_layers)) {
+ view_layer_ = view_layer;
+
if (space_outliner_.filter & SO_FILTER_NO_VIEW_LAYERS) {
if (view_layer != source_data.view_layer) {
continue;
}
- }
- TreeElement &te_view_layer = *outliner_add_element(
- &space_outliner_, &tree, scene, nullptr, TSE_R_LAYER, 0);
- TREESTORE(&te_view_layer)->flag &= ~TSE_CLOSED;
- te_view_layer.name = view_layer->name;
- te_view_layer.directdata = view_layer;
- view_layer_ = view_layer;
-
- if (space_outliner_.filter & SO_FILTER_NO_COLLECTION) {
- /* Show objects in the view layer. */
- for (Base *base : List<Base>(view_layer_->object_bases)) {
- TreeElement *te_object = outliner_add_element(&space_outliner_,
- &te_view_layer.subtree,
- base->object,
- &te_view_layer,
- TSE_SOME_ID,
- 0);
- te_object->directdata = base;
- }
-
- if (show_children) {
- outliner_make_object_parent_hierarchy(&tree);
- }
+ add_view_layer(*scene, tree, (TreeElement *)nullptr);
}
else {
- /* Show collections in the view layer. */
- TreeElement &ten = *outliner_add_element(&space_outliner_,
- &te_view_layer.subtree,
- source_data.scene,
- &te_view_layer,
- TSE_VIEW_COLLECTION_BASE,
- 0);
- ten.name = IFACE_("Scene Collection");
- TREESTORE(&ten)->flag &= ~TSE_CLOSED;
-
- add_view_layer(ten.subtree, ten);
- if (show_children) {
- add_layer_collection_objects_children(ten);
- }
+ TreeElement &te_view_layer = *outliner_add_element(
+ &space_outliner_, &tree, scene, nullptr, TSE_R_LAYER, 0);
+ TREESTORE(&te_view_layer)->flag &= ~TSE_CLOSED;
+ te_view_layer.name = view_layer->name;
+ te_view_layer.directdata = view_layer;
+
+ add_view_layer(*scene, te_view_layer.subtree, &te_view_layer);
}
}
return tree;
}
-void TreeDisplayViewLayer::add_view_layer(ListBase &tree, TreeElement &parent)
+void TreeDisplayViewLayer::add_view_layer(Scene &scene, ListBase &tree, TreeElement *parent)
{
- /* First layer collection is for master collection, don't show it. */
- LayerCollection *lc = static_cast<LayerCollection *>(view_layer_->layer_collections.first);
- if (lc == nullptr) {
- return;
+ const bool show_children = (space_outliner_.filter & SO_FILTER_NO_CHILDREN) == 0;
+
+ if (space_outliner_.filter & SO_FILTER_NO_COLLECTION) {
+ /* Show objects in the view layer. */
+ for (Base *base : List<Base>(view_layer_->object_bases)) {
+ TreeElement *te_object = outliner_add_element(
+ &space_outliner_, &tree, base->object, parent, TSE_SOME_ID, 0);
+ te_object->directdata = base;
+ }
+
+ if (show_children) {
+ outliner_make_object_parent_hierarchy(&tree);
+ }
}
+ else {
+ /* Show collections in the view layer. */
+ TreeElement &ten = *outliner_add_element(
+ &space_outliner_, &tree, &scene, parent, TSE_VIEW_COLLECTION_BASE, 0);
+ ten.name = IFACE_("Scene Collection");
+ TREESTORE(&ten)->flag &= ~TSE_CLOSED;
+
+ /* First layer collection is for master collection, don't show it. */
+ LayerCollection *lc = static_cast<LayerCollection *>(view_layer_->layer_collections.first);
+ if (lc == nullptr) {
+ return;
+ }
- add_layer_collections_recursive(tree, lc->layer_collections, parent);
- if (show_objects_) {
- add_layer_collection_objects(tree, *lc, parent);
+ add_layer_collections_recursive(ten.subtree, lc->layer_collections, ten);
+ if (show_objects_) {
+ add_layer_collection_objects(ten.subtree, *lc, ten);
+ }
+ if (show_children) {
+ add_layer_collection_objects_children(ten);
+ }
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 9669ca2d7c2..8371a634a78 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -2479,10 +2479,12 @@ void draw_timeline_seq_display(const bContext *C, ARegion *region)
const SpaceSeq *sseq = CTX_wm_space_seq(C);
View2D *v2d = &region->v2d;
- if (scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) {
+ if (scene->ed != NULL) {
UI_view2d_view_ortho(v2d);
draw_cache_view(C);
- draw_overlap_frame_indicator(scene, v2d);
+ if (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) {
+ draw_overlap_frame_indicator(scene, v2d);
+ }
UI_view2d_view_restore(C);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 45c6931364d..75cf8542f67 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -2414,6 +2414,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
(LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_FREE_NO_MAIN));
seqbase_clipboard_frame = scene->r.cfra;
+ SEQ_clipboard_active_seq_name_store(scene);
/* Remove anything that references the current scene. */
LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
@@ -2504,6 +2505,10 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
BLI_movelisttolist(ed->seqbasep, &nseqbase);
for (iseq = iseq_first; iseq; iseq = iseq->next) {
+ if (SEQ_clipboard_pasted_seq_was_active(iseq)) {
+ SEQ_select_active_set(scene, iseq);
+ }
+
/* Make sure, that pasted strips have unique names. */
SEQ_ensure_unique_name(iseq, scene);
/* Translate after name has been changed, otherwise this will affect animdata of original
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index 8cc8b4a007b..5d857f62b47 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -624,8 +624,6 @@ static void vectorscope_put_cross(uchar r, uchar g, uchar b, char *tgt, int w, i
{
float rgb[3], yuv[3];
char *p;
- int x = 0;
- int y = 0;
rgb[0] = (float)r / 255.0f;
rgb[1] = (float)g / 255.0f;
@@ -638,8 +636,8 @@ static void vectorscope_put_cross(uchar r, uchar g, uchar b, char *tgt, int w, i
r = 255;
}
- for (y = -size; y <= size; y++) {
- for (x = -size; x <= size; x++) {
+ for (int y = -size; y <= size; y++) {
+ for (int x = -size; x <= size; x++) {
char *q = p + 4 * (y * w + x);
q[0] = r;
q[1] = g;
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index 1ea6593588a..e903feeec1b 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../gpu
../../makesdna
../../makesrna
+ ../../nodes
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
@@ -34,8 +35,8 @@ set(INC
set(SRC
space_spreadsheet.cc
- spreadsheet_context.cc
spreadsheet_column.cc
+ spreadsheet_context.cc
spreadsheet_data_source.cc
spreadsheet_data_source_geometry.cc
spreadsheet_dataset_draw.cc
@@ -46,10 +47,10 @@ set(SRC
spreadsheet_row_filter.cc
spreadsheet_row_filter_ui.cc
- spreadsheet_context.hh
spreadsheet_cell_value.hh
spreadsheet_column.hh
spreadsheet_column_values.hh
+ spreadsheet_context.hh
spreadsheet_data_source.hh
spreadsheet_data_source_geometry.hh
spreadsheet_dataset_draw.hh
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index e42f70611c4..e38c70afd0f 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -31,11 +31,15 @@
#include "ED_spreadsheet.h"
+#include "NOD_geometry_nodes_eval_log.hh"
+
#include "bmesh.h"
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
+namespace geo_log = blender::nodes::geometry_nodes_eval_log;
+
namespace blender::ed::spreadsheet {
void GeometryDataSource::foreach_default_column_ids(
@@ -436,13 +440,18 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
}
}
else {
- if (object_eval->runtime.geometry_set_previews != nullptr) {
- GHash *ghash = (GHash *)object_eval->runtime.geometry_set_previews;
- const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet);
- GeometrySet *geometry_set_preview = (GeometrySet *)BLI_ghash_lookup_default(
- ghash, POINTER_FROM_UINT(key), nullptr);
- if (geometry_set_preview != nullptr) {
- geometry_set = *geometry_set_preview;
+ const geo_log::NodeLog *node_log =
+ geo_log::ModifierLog::find_node_by_spreadsheet_editor_context(*sspreadsheet);
+ if (node_log != nullptr) {
+ for (const geo_log::SocketLog &input_log : node_log->input_logs()) {
+ if (const geo_log::GeometryValueLog *geo_value_log =
+ dynamic_cast<const geo_log::GeometryValueLog *>(input_log.value())) {
+ const GeometrySet *full_geometry = geo_value_log->full_geometry();
+ if (full_geometry != nullptr) {
+ geometry_set = *full_geometry;
+ break;
+ }
+ }
}
}
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc
index 5b5c5ed0b04..abbad8c7088 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc
@@ -38,9 +38,9 @@ namespace blender::ed::spreadsheet {
* Definition for the component->attribute-domain hierarchy.
* Constructed at compile time.
*
- * \warning: Order of attribute-domains matters! It __must__ match the #AttributeDomain definition
- * and fill gaps with unset optionals (i.e. `std::nullopt`). Would be nice to use array
- * designators for this (which C++ doesn't support).
+ * \warning Order of attribute-domains matters! It __must__ match the #AttributeDomain
+ * definition and fill gaps with unset optionals (i.e. `std::nullopt`). Would be nice to use
+ * array designators for this (which C++ doesn't support).
*/
constexpr DatasetComponentLayoutInfo DATASET_layout_hierarchy[] = {
{
diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c
index f55db8c3cc9..80af7d8c9f6 100644
--- a/source/blender/editors/space_text/text_undo.c
+++ b/source/blender/editors/space_text/text_undo.c
@@ -265,7 +265,7 @@ void ED_text_undosys_type(UndoType *ut)
ut->step_foreach_ID_ref = text_undosys_foreach_ID_ref;
- ut->flags = UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE;
+ ut->flags = UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE | UNDOTYPE_FLAG_DECODE_ACTIVE_STEP;
ut->step_size = sizeof(TextUndoStep);
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index d5e52785937..3428a738dde 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -39,6 +39,8 @@
#include "BLT_translation.h"
+#include "BLI_array_utils.h"
+#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -112,10 +114,94 @@ typedef struct {
float ob_dims[3];
/* Floats only (treated as an array). */
TransformMedian ve_median, median;
+ bool tag_for_update;
} TransformProperties;
#define TRANSFORM_MEDIAN_ARRAY_LEN (sizeof(TransformMedian) / sizeof(float))
+static TransformProperties *v3d_transform_props_ensure(View3D *v3d);
+
+/* -------------------------------------------------------------------- */
+/** \name Edit Mesh Partial Updates
+ * \{ */
+
+static void *editmesh_partial_update_begin_fn(struct bContext *UNUSED(C),
+ const struct uiBlockInteraction_Params *params,
+ void *arg1)
+{
+ const int retval_test = B_TRANSFORM_PANEL_MEDIAN;
+ if (BLI_array_findindex(
+ params->unique_retval_ids, params->unique_retval_ids_len, &retval_test) == -1) {
+ return NULL;
+ }
+
+ BMEditMesh *em = arg1;
+
+ int verts_mask_count = 0;
+ BMIter iter;
+ BMVert *eve;
+ int i;
+
+ BLI_bitmap *verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ continue;
+ }
+ BLI_BITMAP_ENABLE(verts_mask, i);
+ verts_mask_count += 1;
+ }
+
+ BMPartialUpdate *bmpinfo = BM_mesh_partial_create_from_verts_group_single(
+ em->bm,
+ &(BMPartialUpdate_Params){
+ .do_tessellate = true,
+ .do_normals = true,
+ },
+ verts_mask,
+ verts_mask_count);
+
+ MEM_freeN(verts_mask);
+
+ return bmpinfo;
+}
+
+static void editmesh_partial_update_end_fn(struct bContext *UNUSED(C),
+ const struct uiBlockInteraction_Params *UNUSED(params),
+ void *UNUSED(arg1),
+ void *user_data)
+{
+ BMPartialUpdate *bmpinfo = user_data;
+ if (bmpinfo == NULL) {
+ return;
+ }
+ BM_mesh_partial_destroy(bmpinfo);
+}
+
+static void editmesh_partial_update_update_fn(
+ struct bContext *C,
+ const struct uiBlockInteraction_Params *UNUSED(params),
+ void *arg1,
+ void *user_data)
+{
+ BMPartialUpdate *bmpinfo = user_data;
+ if (bmpinfo == NULL) {
+ return;
+ }
+
+ View3D *v3d = CTX_wm_view3d(C);
+ TransformProperties *tfp = v3d_transform_props_ensure(v3d);
+ if (tfp->tag_for_update == false) {
+ return;
+ }
+ tfp->tag_for_update = false;
+
+ BMEditMesh *em = arg1;
+
+ BKE_editmesh_looptri_and_normals_calc_with_partial(em, bmpinfo);
+}
+
+/** \} */
+
/* Helper function to compute a median changed value,
* when the value should be clamped in [0.0, 1.0].
* Returns either 0.0, 1.0 (both can be applied directly), a positive scale factor
@@ -840,6 +926,20 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
UI_block_align_end(block);
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_mesh;
+ if (em != NULL) {
+ UI_block_interaction_set(block,
+ &(uiBlockInteraction_CallbackData){
+ .begin_fn = editmesh_partial_update_begin_fn,
+ .end_fn = editmesh_partial_update_end_fn,
+ .update_fn = editmesh_partial_update_update_fn,
+ .arg1 = em,
+ });
+ }
+ }
}
else { /* apply */
memcpy(&ve_median_basis, &tfp->ve_median, sizeof(tfp->ve_median));
@@ -927,9 +1027,8 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
if (apply_vcos) {
- /* TODO: use the #BKE_editmesh_looptri_and_normals_calc_with_partial
- * This requires begin/end states for UI interaction (which currently aren't supported). */
- BKE_editmesh_looptri_and_normals_calc(em);
+ /* Tell the update callback to run. */
+ tfp->tag_for_update = true;
}
/* Edges */
@@ -1152,7 +1251,7 @@ static void do_view3d_vgroup_buttons(bContext *C, void *UNUSED(arg), int event)
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = view_layer->basact->object;
ED_vgroup_vert_active_mirror(ob, event - B_VGRP_PNL_EDIT_SINGLE);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
}
@@ -1466,7 +1565,7 @@ static void v3d_posearmature_buts(uiLayout *layout, Object *ob)
/* XXX: RNA buts show data in native types (i.e. quats, 4-component axis/angle, etc.)
* but old-school UI shows in eulers always. Do we want to be able to still display in Eulers?
- * Maybe needs RNA/ui options to display rotations as different types... */
+ * Maybe needs RNA/UI options to display rotations as different types. */
v3d_transform_butsR(col, &pchanptr);
}
@@ -1570,7 +1669,7 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event
case B_TRANSFORM_PANEL_MEDIAN:
if (ob) {
v3d_editvertex_buts(NULL, v3d, ob, 1.0);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
}
break;
case B_TRANSFORM_PANEL_DIMS:
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index ea9d9a8c010..c97ba7ba7e9 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1404,7 +1404,7 @@ static void draw_selected_name(
/* color depends on whether there is a keyframe */
if (id_frame_has_keyframe(
- (ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) {
+ (ID *)ob, /* BKE_scene_ctime_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) {
UI_FontThemeColor(font_id, TH_TIME_KEYFRAME);
}
else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) {
diff --git a/source/blender/editors/space_view3d/view3d_navigate_fly.c b/source/blender/editors/space_view3d/view3d_navigate_fly.c
index e2fa0fdc6a5..5752837c40f 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_fly.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_fly.c
@@ -122,7 +122,7 @@ void fly_modal_keymap(wmKeyConfig *keyconf)
{FLY_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""},
{FLY_MODAL_AXIS_LOCK_X, "AXIS_LOCK_X", 0, "X Axis Correction", "X axis correction (toggle)"},
- {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "X Axis Correction", "Z axis correction (toggle)"},
+ {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "Z Axis Correction", "Z axis correction (toggle)"},
{FLY_MODAL_PRECISION_ENABLE, "PRECISION_ENABLE", 0, "Precision", ""},
{FLY_MODAL_PRECISION_DISABLE, "PRECISION_DISABLE", 0, "Precision (Off)", ""},
diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index 435d74aa591..09936b41a74 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -98,9 +98,10 @@ enum {
WALK_MODAL_JUMP,
WALK_MODAL_JUMP_STOP,
WALK_MODAL_TELEPORT,
- WALK_MODAL_TOGGLE,
+ WALK_MODAL_GRAVITY_TOGGLE,
WALK_MODAL_ACCELERATE,
WALK_MODAL_DECELERATE,
+ WALK_MODAL_AXIS_LOCK_Z,
};
enum {
@@ -129,6 +130,18 @@ typedef enum eWalkGravityState {
WALK_GRAVITY_STATE_ON,
} eWalkGravityState;
+/* Relative view axis z axis locking. */
+typedef enum eWalkLockState {
+ /* Disabled. */
+ WALK_AXISLOCK_STATE_OFF = 0,
+
+ /* Moving. */
+ WALK_AXISLOCK_STATE_ACTIVE = 2,
+
+ /* Done moving, it cannot be activated again. */
+ WALK_AXISLOCK_STATE_DONE = 3,
+} eWalkLockState;
+
/* Called in transform_ops.c, on each regeneration of key-maps. */
void walk_modal_keymap(wmKeyConfig *keyconf)
{
@@ -164,7 +177,9 @@ void walk_modal_keymap(wmKeyConfig *keyconf)
{WALK_MODAL_JUMP, "JUMP", 0, "Jump", "Jump when in walk mode"},
{WALK_MODAL_JUMP_STOP, "JUMP_STOP", 0, "Jump (Off)", "Stop pushing jump"},
- {WALK_MODAL_TOGGLE, "GRAVITY_TOGGLE", 0, "Toggle Gravity", "Toggle gravity effect"},
+ {WALK_MODAL_GRAVITY_TOGGLE, "GRAVITY_TOGGLE", 0, "Toggle Gravity", "Toggle gravity effect"},
+
+ {WALK_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "Z Axis Correction", "Z axis correction"},
{0, NULL, 0, NULL, NULL},
};
@@ -292,6 +307,10 @@ typedef struct WalkInfo {
/** To use for fast/slow speeds. */
float speed_factor;
+ eWalkLockState zlock;
+ /** Nicer dynamics. */
+ float zlock_momentum;
+
struct SnapObjectContext *snap_context;
struct View3DCameraControl *v3d_camera_control;
@@ -540,6 +559,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->jump_height = U.walk_navigation.jump_height;
walk->speed = U.walk_navigation.walk_speed;
walk->speed_factor = U.walk_navigation.walk_speed_factor;
+ walk->zlock = WALK_AXISLOCK_STATE_OFF;
walk->gravity_state = WALK_GRAVITY_STATE_OFF;
@@ -708,8 +728,6 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
walk->is_cursor_absolute = true;
copy_v2_v2_int(walk->prev_mval, event->mval);
copy_v2_v2_int(walk->center_mval, event->mval);
- /* Without this we can't turn 180d with the default speed of 1.0. */
- walk->mouse_speed *= 4.0f;
}
#endif /* USE_TABLET_SUPPORT */
@@ -941,7 +959,7 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
#undef JUMP_TIME_MAX
#undef JUMP_SPEED_MIN
- case WALK_MODAL_TOGGLE:
+ case WALK_MODAL_GRAVITY_TOGGLE:
if (walk->navigation_mode == WALK_MODE_GRAVITY) {
walk_navigation_mode_set(walk, WALK_MODE_FREE);
}
@@ -949,6 +967,13 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
walk_navigation_mode_set(walk, WALK_MODE_GRAVITY);
}
break;
+
+ case WALK_MODAL_AXIS_LOCK_Z:
+ if (walk->zlock != WALK_AXISLOCK_STATE_DONE) {
+ walk->zlock = WALK_AXISLOCK_STATE_ACTIVE;
+ walk->zlock_momentum = 0.0f;
+ }
+ break;
}
}
}
@@ -982,12 +1007,14 @@ static float getVelocityZeroTime(const float gravity, const float velocity)
static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
{
-#define WALK_ROTATE_RELATIVE_FAC 2.2f /* More is faster, relative to region size. */
-#define WALK_ROTATE_CONSTANT_FAC DEG2RAD(0.15f) /* More is faster, radians per-pixel. */
+#define WALK_ROTATE_TABLET_FAC 8.8f /* Higher is faster, relative to region size. */
+#define WALK_ROTATE_CONSTANT_FAC DEG2RAD(0.15f) /* Higher is faster, radians per-pixel. */
#define WALK_TOP_LIMIT DEG2RADF(85.0f)
#define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f)
#define WALK_MOVE_SPEED base_speed
#define WALK_BOOST_FACTOR ((void)0, walk->speed_factor)
+#define WALK_ZUP_CORRECT_FAC 0.1f /* Amount to correct per step. */
+#define WALK_ZUP_CORRECT_ACCEL 0.05f /* Increase upright momentum each step. */
RegionView3D *rv3d = walk->rv3d;
ARegion *region = walk->region;
@@ -1022,20 +1049,25 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
/* Should we redraw? */
if ((walk->active_directions) || moffset[0] || moffset[1] ||
- walk->teleport.state == WALK_TELEPORT_STATE_ON ||
- walk->gravity_state != WALK_GRAVITY_STATE_OFF || is_confirm) {
+ walk->zlock == WALK_AXISLOCK_STATE_ACTIVE ||
+ walk->gravity_state != WALK_GRAVITY_STATE_OFF ||
+ walk->teleport.state == WALK_TELEPORT_STATE_ON || is_confirm) {
float dvec_tmp[3];
/* time how fast it takes for us to redraw,
* this is so simple scenes don't walk too fast */
double time_current;
float time_redraw;
+ float time_redraw_clamped;
#ifdef NDOF_WALK_DRAW_TOOMUCH
walk->redraw = 1;
#endif
time_current = PIL_check_seconds_timer();
time_redraw = (float)(time_current - walk->time_lastdraw);
+ /* Clamp redraw time to avoid jitter in roll correction. */
+ time_redraw_clamped = min_ff(0.05f, time_redraw);
+
walk->time_lastdraw = time_current;
/* base speed in m/s */
@@ -1064,7 +1096,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
#ifdef USE_TABLET_SUPPORT
if (walk->is_cursor_absolute) {
y /= region->winy;
- y *= WALK_ROTATE_RELATIVE_FAC;
+ y *= WALK_ROTATE_TABLET_FAC;
}
else
#endif
@@ -1113,7 +1145,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
#ifdef USE_TABLET_SUPPORT
if (walk->is_cursor_absolute) {
x /= region->winx;
- x *= WALK_ROTATE_RELATIVE_FAC;
+ x *= WALK_ROTATE_TABLET_FAC;
}
else
#endif
@@ -1128,6 +1160,32 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
axis_angle_to_quat_single(tmp_quat, 'Z', x);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
}
+
+ if (walk->zlock == WALK_AXISLOCK_STATE_ACTIVE) {
+ float upvec[3];
+ copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
+ mul_m3_v3(mat, upvec);
+
+ /* Make sure we have some z rolling. */
+ if (fabsf(upvec[2]) > 0.00001f) {
+ float roll = upvec[2] * 5.0f;
+ /* Rotate the view about this axis. */
+ copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f);
+ mul_m3_v3(mat, upvec);
+ /* Rotate about the relative up vec. */
+ axis_angle_to_quat(tmp_quat,
+ upvec,
+ roll * time_redraw_clamped * walk->zlock_momentum *
+ WALK_ZUP_CORRECT_FAC);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
+
+ walk->zlock_momentum += WALK_ZUP_CORRECT_ACCEL;
+ }
+ else {
+ /* Lock fixed, don't need to check it ever again. */
+ walk->zlock = WALK_AXISLOCK_STATE_DONE;
+ }
+ }
}
/* WASD - 'move' translation code */
@@ -1318,7 +1376,8 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
add_v3_v3(rv3d->ofs, dvec_tmp);
if (rv3d->persp == RV3D_CAMOB) {
- walk->need_rotation_keyframe |= (moffset[0] || moffset[1]);
+ walk->need_rotation_keyframe |= (moffset[0] || moffset[1] ||
+ walk->zlock == WALK_AXISLOCK_STATE_ACTIVE);
walk->need_translation_keyframe |= (len_squared_v3(dvec_tmp) > FLT_EPSILON);
walkMoveCamera(
C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm);
@@ -1333,7 +1392,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
}
return OPERATOR_FINISHED;
-#undef WALK_ROTATE_RELATIVE_FAC
+#undef WALK_ROTATE_TABLET_FAC
#undef WALK_TOP_LIMIT
#undef WALK_BOTTOM_LIMIT
#undef WALK_MOVE_SPEED
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index a19e92f229a..4482e5897ca 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -511,47 +511,47 @@ static int snap_selected_to_location(bContext *C,
for (int ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob = objects[ob_index];
+ if (ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) {
+ continue;
+ }
- if ((ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) == 0) {
-
- float cursor_parent[3]; /* parent-relative */
-
- if (use_offset) {
- add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global);
- }
- else {
- copy_v3_v3(cursor_parent, snap_target_global);
- }
+ float cursor_parent[3]; /* parent-relative */
- sub_v3_v3(cursor_parent, ob->obmat[3]);
+ if (use_offset) {
+ add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global);
+ }
+ else {
+ copy_v3_v3(cursor_parent, snap_target_global);
+ }
- if (ob->parent) {
- float originmat[3][3], parentmat[4][4];
- /* Use the evaluated object here because sometimes
- * `ob->parent->runtime.curve_cache` is required. */
- BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ sub_v3_v3(cursor_parent, ob->obmat[3]);
- BKE_object_get_parent_matrix(ob_eval, ob_eval->parent, parentmat);
- mul_m3_m4m4(originmat, parentmat, ob->parentinv);
- invert_m3_m3(imat, originmat);
- mul_m3_v3(imat, cursor_parent);
- }
- if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
- ob->loc[0] += cursor_parent[0];
- }
- if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
- ob->loc[1] += cursor_parent[1];
- }
- if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
- ob->loc[2] += cursor_parent[2];
- }
+ if (ob->parent) {
+ float originmat[3][3], parentmat[4][4];
+ /* Use the evaluated object here because sometimes
+ * `ob->parent->runtime.curve_cache` is required. */
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+
+ BKE_object_get_parent_matrix(ob_eval, ob_eval->parent, parentmat);
+ mul_m3_m4m4(originmat, parentmat, ob->parentinv);
+ invert_m3_m3(imat, originmat);
+ mul_m3_v3(imat, cursor_parent);
+ }
+ if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
+ ob->loc[0] += cursor_parent[0];
+ }
+ if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
+ ob->loc[1] += cursor_parent[1];
+ }
+ if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
+ ob->loc[2] += cursor_parent[2];
+ }
- /* auto-keyframing */
- ED_autokeyframe_object(C, scene, ob, ks);
+ /* auto-keyframing */
+ ED_autokeyframe_object(C, scene, ob, ks);
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
- }
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
}
if (objects) {
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index c1ee6edfef6..18cd62a0baf 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -2094,7 +2094,7 @@ void recalcData_mesh(TransInfo *t)
tc_mesh_partial_types_calc(t, &partial_state);
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY_DEFORM);
tc_mesh_partial_update(t, tc, &partial_state);
}
diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c
index 3b1191a3401..2db3e259153 100644
--- a/source/blender/editors/transform/transform_convert_mesh_edge.c
+++ b/source/blender/editors/transform/transform_convert_mesh_edge.c
@@ -28,6 +28,7 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c
index d91a2a8be4b..61397b6ef4b 100644
--- a/source/blender/editors/transform/transform_convert_mesh_uv.c
+++ b/source/blender/editors/transform/transform_convert_mesh_uv.c
@@ -30,6 +30,7 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_mesh_mapping.h"
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index c217478bd04..ee6cb391fdc 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -153,7 +153,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
float rot[3][3], scale[3];
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = BKE_scene_ctime_get(scene);
/* only use rigid body transform if simulation is running,
* avoids problems with initial setup of rigid bodies */
@@ -978,7 +978,7 @@ void special_aftertrans_update__object(bContext *C, TransInfo *t)
/* restore rigid body transform */
if (ob->rigidbody_object && canceled) {
- float ctime = BKE_scene_frame_get(t->scene);
+ float ctime = BKE_scene_ctime_get(t->scene);
if (BKE_rigidbody_check_sim_running(t->scene->rigidbody_world, ctime)) {
BKE_rigidbody_aftertrans_update(ob,
td->ext->oloc,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 8a4c8f410c0..2d98d756dba 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -535,7 +535,7 @@ static void iter_snap_objects(SnapObjectContext *sctx,
* \{ */
/* Store all ray-hits
- * Support for storing all depths, not just the first (raycast 'all') */
+ * Support for storing all depths, not just the first (ray-cast 'all'). */
struct RayCastAll_Data {
void *bvhdata;
@@ -626,7 +626,7 @@ static bool raycast_tri_backface_culling_test(
return dot_v3v3(no, dir) < 0.0f;
}
-/* Callback to raycast with backface culling (Mesh). */
+/* Callback to ray-cast with back-face culling (#Mesh). */
static void mesh_looptri_raycast_backface_culling_cb(void *userdata,
int index,
const BVHTreeRay *ray,
@@ -653,7 +653,7 @@ static void mesh_looptri_raycast_backface_culling_cb(void *userdata,
}
}
-/* Callback to raycast with backface culling (EditMesh). */
+/* Callback to ray-cast with back-face culling (#EditMesh). */
static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
int index,
const BVHTreeRay *ray,
diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c
index 93948b5ae1b..56bcbc63de1 100644
--- a/source/blender/editors/uvedit/uvedit_islands.c
+++ b/source/blender/editors/uvedit/uvedit_islands.c
@@ -36,6 +36,7 @@
#include "BLI_math.h"
#include "BLI_rect.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index eb4ca2e13b2..f97403a0919 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -2154,7 +2154,7 @@ static void p_collapse_cost_vertex(PVert *vert, float *r_mincost, PEdge **r_mine
static void p_chart_post_collapse_flush(PChart *chart, PEdge *collapsed)
{
- /* move to collapsed_ */
+ /* Move to `collapsed_*`. */
PVert *v, *nextv = NULL, *verts = chart->verts;
PEdge *e, *nexte = NULL, *edges = chart->edges, *laste = NULL;
@@ -2224,7 +2224,7 @@ static void p_chart_post_collapse_flush(PChart *chart, PEdge *collapsed)
static void p_chart_post_split_flush(PChart *chart)
{
- /* move from collapsed_ */
+ /* Move from `collapsed_*`. */
PVert *v, *nextv = NULL;
PEdge *e, *nexte = NULL;
@@ -2259,7 +2259,7 @@ static void p_chart_post_split_flush(PChart *chart)
static void p_chart_simplify_compute(PChart *chart)
{
/* Computes a list of edge collapses / vertex splits. The collapsed
- * simplices go in the chart->collapsed_* lists, The original and
+ * simplices go in the `chart->collapsed_*` lists, The original and
* collapsed may then be view as stacks, where the next collapse/split
* is at the top of the respective lists. */