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:
authorJoseph Eagar <joeedh@gmail.com>2021-09-18 02:22:10 +0300
committerJoseph Eagar <joeedh@gmail.com>2021-09-18 02:22:10 +0300
commit85d274a60c03b067efaddeda921f0edf1c0982b3 (patch)
treebb78b124f2d05e3ebe6e3f5a2363d89fe012ecfe /source/blender/editors
parent6648f82ef7d6a15c8e8fb5474bdee6d2e7853a26 (diff)
parent6cf734a2e5d2496d1b2d33bc7613b56a9f9fc2ec (diff)
Merge branch 'master' into sculpt-dev
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/anim_deps.c18
-rw-r--r--source/blender/editors/animation/anim_draw.c1
-rw-r--r--source/blender/editors/animation/anim_filter.c91
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c30
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c2
-rw-r--r--source/blender/editors/animation/anim_ops.c2
-rw-r--r--source/blender/editors/animation/keyframes_draw.c49
-rw-r--r--source/blender/editors/animation/keyframes_general.c35
-rw-r--r--source/blender/editors/animation/keyframes_keylist.cc482
-rw-r--r--source/blender/editors/animation/keyframing.c27
-rw-r--r--source/blender/editors/armature/armature_add.c4
-rw-r--r--source/blender/editors/armature/pose_select.c26
-rw-r--r--source/blender/editors/armature/pose_slide.c4
-rw-r--r--source/blender/editors/curve/editcurve.c4
-rw-r--r--source/blender/editors/curve/editcurve_add.c9
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt4
-rw-r--r--source/blender/editors/gizmo_library/CMakeLists.txt1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_utils.c33
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c23
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c16
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c28
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c8
-rw-r--r--source/blender/editors/include/ED_anim_api.h4
-rw-r--r--source/blender/editors/include/ED_gpencil.h7
-rw-r--r--source/blender/editors/include/ED_image.h1
-rw-r--r--source/blender/editors/include/ED_keyframes_keylist.h14
-rw-r--r--source/blender/editors/include/ED_object.h1
-rw-r--r--source/blender/editors/include/ED_transform.h15
-rw-r--r--source/blender/editors/include/ED_view3d.h10
-rw-r--r--source/blender/editors/include/UI_icons.h6
-rw-r--r--source/blender/editors/include/UI_interface.h12
-rw-r--r--source/blender/editors/interface/interface_context_menu.c70
-rw-r--r--source/blender/editors/interface/interface_handlers.c19
-rw-r--r--source/blender/editors/interface/interface_layout.c8
-rw-r--r--source/blender/editors/interface/interface_template_asset_view.cc26
-rw-r--r--source/blender/editors/interface/interface_template_list.cc9
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.c3
-rw-r--r--source/blender/editors/interface/interface_templates.c6
-rw-r--r--source/blender/editors/interface/interface_widgets.c11
-rw-r--r--source/blender/editors/mask/mask_select.c2
-rw-r--r--source/blender/editors/mesh/editmesh_add.c14
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c10
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c32
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c4
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c10
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c4
-rw-r--r--source/blender/editors/mesh/editmesh_rip_edge.c2
-rw-r--r--source/blender/editors/mesh/editmesh_select.c11
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c2
-rw-r--r--source/blender/editors/mesh/meshtools.c5
-rw-r--r--source/blender/editors/object/CMakeLists.txt5
-rw-r--r--source/blender/editors/object/object_add.c49
-rw-r--r--source/blender/editors/object/object_constraint.c7
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c238
-rw-r--r--source/blender/editors/object/object_intern.h5
-rw-r--r--source/blender/editors/object/object_modifier.c53
-rw-r--r--source/blender/editors/object/object_ops.c5
-rw-r--r--source/blender/editors/object/object_relations.c109
-rw-r--r--source/blender/editors/screen/area.c10
-rw-r--r--source/blender/editors/screen/screen_context.c49
-rw-r--r--source/blender/editors/screen/screen_geometry.c4
-rw-r--r--source/blender/editors/screen/screen_intern.h1
-rw-r--r--source/blender/editors/screen/screen_ops.c54
-rw-r--r--source/blender/editors/screen/screendump.c60
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c8
-rw-r--r--source/blender/editors/space_action/action_edit.c4
-rw-r--r--source/blender/editors/space_action/action_select.c3
-rw-r--r--source/blender/editors/space_action/space_action.c4
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c6
-rw-r--r--source/blender/editors/space_clip/tracking_select.c2
-rw-r--r--source/blender/editors/space_file/file_intern.h3
-rw-r--r--source/blender/editors/space_file/filelist.c8
-rw-r--r--source/blender/editors/space_file/filesel.c3
-rw-r--r--source/blender/editors/space_file/space_file.c17
-rw-r--r--source/blender/editors/space_graph/graph_select.c2
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c46
-rw-r--r--source/blender/editors/space_graph/space_graph.c4
-rw-r--r--source/blender/editors/space_image/image_edit.c6
-rw-r--r--source/blender/editors/space_image/image_ops.c9
-rw-r--r--source/blender/editors/space_image/space_image.c8
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c23
-rw-r--r--source/blender/editors/space_node/drawnode.cc17
-rw-r--r--source/blender/editors/space_node/node_add.cc4
-rw-r--r--source/blender/editors/space_node/node_draw.cc83
-rw-r--r--source/blender/editors/space_node/node_edit.cc31
-rw-r--r--source/blender/editors/space_node/node_relationships.cc4
-rw-r--r--source/blender/editors/space_node/node_select.cc2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c14
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c11
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_sequencer.cc2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c24
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c84
-rw-r--r--source/blender/editors/space_sequencer/sequencer_modifier.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_proxy.c6
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c430
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c4
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh5
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc29
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc17
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc2
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c102
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c64
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c171
-rw-r--r--source/blender/editors/transform/transform.h3
-rw-r--r--source/blender/editors/transform/transform_convert_action.c20
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c32
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c8
-rw-r--r--source/blender/editors/transform/transform_generics.c15
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c14
-rw-r--r--source/blender/editors/transform/transform_mode.c12
-rw-r--r--source/blender/editors/transform/transform_ops.c7
-rw-r--r--source/blender/editors/transform/transform_orientations.c50
-rw-r--r--source/blender/editors/transform/transform_orientations.h3
-rw-r--r--source/blender/editors/transform/transform_snap_object.c4
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c6
-rw-r--r--source/blender/editors/undo/ed_undo.c7
-rw-r--r--source/blender/editors/util/ed_util_imbuf.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_rip.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c2
132 files changed, 2226 insertions, 1130 deletions
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 42fdb714127..97679723d84 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -206,21 +206,17 @@ static void animchan_sync_fcurve_scene(bAnimListElem *ale)
BLI_assert(GS(owner_id->name) == ID_SCE);
Scene *scene = (Scene *)owner_id;
FCurve *fcu = (FCurve *)ale->data;
+ Sequence *seq = NULL;
- /* only affect if F-Curve involves sequence_editor.sequences */
- if (!strstr(fcu->rna_path, "sequences_all")) {
+ /* Only affect if F-Curve involves sequence_editor.sequences. */
+ char seq_name[sizeof(seq->name)];
+ if (!BLI_str_quoted_substr(fcu->rna_path, "sequences_all[", seq_name, sizeof(seq_name))) {
return;
}
- Editing *ed = SEQ_editing_get(scene, false);
-
- /* get strip name, and check if this strip is selected */
- char *seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all[");
- if (seq_name == NULL) {
- return;
- }
-
- Sequence *seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false);
+ /* Check if this strip is selected. */
+ Editing *ed = SEQ_editing_get(scene);
+ seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false);
MEM_freeN(seq_name);
if (seq == NULL) {
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 6d272bfc180..993d10cf303 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -521,6 +521,7 @@ static bool find_prev_next_keyframes(struct bContext *C, int *r_nextfra, int *r_
MaskLayer *masklay = BKE_mask_layer_active(mask);
mask_to_keylist(&ads, masklay, keylist);
}
+ ED_keylist_prepare_for_direct_access(keylist);
/* TODO(jbakker): Keylists are ordered, no need to do any searching at all. */
/* find matching keyframe in the right direction */
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 020518b5813..b12e0ae5cab 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -1061,20 +1061,17 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id
if (GS(owner_id->name) == ID_OB) {
Object *ob = (Object *)owner_id;
+ bPoseChannel *pchan = NULL;
+ char bone_name[sizeof(pchan->name)];
- /* only consider if F-Curve involves pose.bones */
- if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) {
-
- /* get bone-name, and check if this bone is selected */
- bPoseChannel *pchan = NULL;
- char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
- if (bone_name) {
- pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
- MEM_freeN(bone_name);
- }
+ /* Only consider if F-Curve involves `pose.bones`. */
+ if (fcu->rna_path &&
+ BLI_str_quoted_substr(fcu->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
+ /* Get bone-name, and check if this bone is selected. */
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
/* check whether to continue or skip */
- if ((pchan) && (pchan->bone)) {
+ if (pchan && pchan->bone) {
/* If only visible channels,
* skip if bone not visible unless user wants channels from hidden data too. */
if (skip_hidden) {
@@ -1101,24 +1098,41 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id
}
else if (GS(owner_id->name) == ID_SCE) {
Scene *scene = (Scene *)owner_id;
-
- /* only consider if F-Curve involves sequence_editor.sequences */
- if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
- Editing *ed = SEQ_editing_get(scene, false);
- Sequence *seq = NULL;
-
+ Sequence *seq = NULL;
+ char seq_name[sizeof(seq->name)];
+
+ /* Only consider if F-Curve involves `sequence_editor.sequences`. */
+ if (fcu->rna_path &&
+ BLI_str_quoted_substr(fcu->rna_path, "sequences_all[", seq_name, sizeof(seq_name))) {
+ /* Get strip name, and check if this strip is selected. */
+ Editing *ed = SEQ_editing_get(scene);
if (ed) {
- /* get strip name, and check if this strip is selected */
- char *seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all[");
- if (seq_name) {
- seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false);
- MEM_freeN(seq_name);
- }
+ seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false);
}
- /* can only add this F-Curve if it is selected */
+ /* Can only add this F-Curve if it is selected. */
if (ads->filterflag & ADS_FILTER_ONLYSEL) {
- if ((seq == NULL) || (seq->flag & SELECT) == 0) {
+
+ /* NOTE(@campbellbarton): The `seq == NULL` check doesn't look right
+ * (compared to other checks in this function which skip data that can't be found).
+ *
+ * This is done since the search for sequence strips doesn't use a global lookup:
+ * - Nested meta-strips are excluded.
+ * - When inside a meta-strip - strips outside the meta-strip excluded.
+ *
+ * Instead, only the strips directly visible to the user are considered for selection.
+ * The NULL check here means everything else is considered unselected and is not shown.
+ *
+ * There is a subtle difference between nodes, pose-bones ... etc
+ * since data-paths that point to missing strips are not shown.
+ * If this is an important difference, the NULL case could perform a global lookup,
+ * only returning `true` if the sequence strip exists elsewhere
+ * (ignoring it's selection state). */
+ if (seq == NULL) {
+ return true;
+ }
+
+ if ((seq->flag & SELECT) == 0) {
return true;
}
}
@@ -1126,22 +1140,21 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id
}
else if (GS(owner_id->name) == ID_NT) {
bNodeTree *ntree = (bNodeTree *)owner_id;
+ bNode *node = NULL;
+ char node_name[sizeof(node->name)];
- /* check for selected nodes */
- if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
- bNode *node = NULL;
-
- /* get strip name, and check if this strip is selected */
- char *node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes[");
- if (node_name) {
- node = nodeFindNodebyName(ntree, node_name);
- MEM_freeN(node_name);
- }
+ /* Check for selected nodes. */
+ if (fcu->rna_path &&
+ (BLI_str_quoted_substr(fcu->rna_path, "nodes[", node_name, sizeof(node_name)))) {
+ /* Get strip name, and check if this strip is selected. */
+ node = nodeFindNodebyName(ntree, node_name);
- /* can only add this F-Curve if it is selected */
- if (ads->filterflag & ADS_FILTER_ONLYSEL) {
- if ((node) && (node->flag & NODE_SELECT) == 0) {
- return true;
+ /* Can only add this F-Curve if it is selected. */
+ if (node) {
+ if (ads->filterflag & ADS_FILTER_ONLYSEL) {
+ if ((node->flag & NODE_SELECT) == 0) {
+ return true;
+ }
}
}
}
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index eda87cf1897..33b4882927a 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -106,23 +106,14 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
* - If a pointer just refers to the ID-block, then don't repeat this info
* since this just introduces clutter.
*/
- if (strstr(fcu->rna_path, "bones") && strstr(fcu->rna_path, "constraints")) {
- /* perform string 'chopping' to get "Bone Name : Constraint Name" */
- char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
- char *constName = BLI_str_quoted_substrN(fcu->rna_path, "constraints[");
+
+ char pchanName[256], constName[256];
+ if (BLI_str_quoted_substr(fcu->rna_path, "bones[", pchanName, sizeof(pchanName)) &&
+ BLI_str_quoted_substr(fcu->rna_path, "constraints[", constName, sizeof(constName))) {
/* assemble the string to display in the UI... */
- structname = BLI_sprintfN(
- "%s : %s", pchanName ? pchanName : "", constName ? constName : "");
+ structname = BLI_sprintfN("%s : %s", pchanName, constName);
free_structname = 1;
-
- /* free the temp names */
- if (pchanName) {
- MEM_freeN(pchanName);
- }
- if (constName) {
- MEM_freeN(constName);
- }
}
else if (ptr.data != ptr.owner_id) {
PropertyRNA *nameprop = RNA_struct_name_property(ptr.type);
@@ -139,18 +130,15 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
* displaying the struct name alone is no meaningful information (and also cannot be
* filtered well), same for modifiers. So display strip name alongside as well. */
if (GS(ptr.owner_id->name) == ID_SCE) {
- if (BLI_str_startswith(fcu->rna_path, "sequence_editor.sequences_all[\"")) {
+ char stripname[256];
+ if (BLI_str_quoted_substr(
+ fcu->rna_path, "sequence_editor.sequences_all[", stripname, sizeof(stripname))) {
if (strstr(fcu->rna_path, ".transform.") || strstr(fcu->rna_path, ".crop.") ||
strstr(fcu->rna_path, ".modifiers[")) {
- char *stripname = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all[");
- const char *structname_all = BLI_sprintfN(
- "%s : %s", stripname ? stripname : "", structname);
+ const char *structname_all = BLI_sprintfN("%s : %s", stripname, structname);
if (free_structname) {
MEM_freeN((void *)structname);
}
- if (stripname) {
- MEM_freeN(stripname);
- }
structname = structname_all;
free_structname = 1;
}
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index d976f5f72ad..d130941b9bc 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -329,6 +329,7 @@ static void motionpath_calculate_update_range(MPathTarget *mpt,
for (FCurve *fcu = fcurve_list->first; fcu != NULL; fcu = fcu->next) {
struct AnimKeylist *keylist = ED_keylist_create();
fcurve_to_keylist(adt, fcu, keylist, 0);
+ ED_keylist_prepare_for_direct_access(keylist);
int fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, keylist, current_frame);
int fcu_efra = motionpath_get_next_next_keyframe(mpt, keylist, current_frame);
@@ -443,6 +444,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
action_to_keylist(adt, adt->action, mpt->keylist, 0);
}
}
+ ED_keylist_prepare_for_direct_access(mpt->keylist);
if (range == ANIMVIZ_CALC_RANGE_CHANGED) {
int mpt_sfra, mpt_efra;
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 6f3277397c5..450d7cd100e 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -105,7 +105,7 @@ static void seq_frame_snap_update_best(const int 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));
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
SeqCollection *strips = SEQ_query_all_strips(seqbase);
int best_frame = 0;
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 61918871b90..ac7db9f4f46 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -30,6 +30,7 @@
#include "BLI_dlrbTree.h"
#include "BLI_listbase.h"
#include "BLI_rect.h"
+#include "BLI_task.h"
#include "DNA_anim_types.h"
#include "DNA_gpencil_types.h"
@@ -346,10 +347,12 @@ static void draw_keylist_block(const DrawKeylistUIData *ctx, const ActKeyColumn
}
static void draw_keylist_blocks(const DrawKeylistUIData *ctx,
- const ListBase * /*ActKeyColumn*/ columns,
+ const ActKeyColumn *keys,
+ const int key_len,
float ypos)
{
- LISTBASE_FOREACH (ActKeyColumn *, ab, columns) {
+ for (int i = 0; i < key_len; i++) {
+ const ActKeyColumn *ab = &keys[i];
draw_keylist_block(ctx, ab, ypos);
}
}
@@ -362,13 +365,15 @@ static bool draw_keylist_is_visible_key(const View2D *v2d, const ActKeyColumn *a
static void draw_keylist_keys(const DrawKeylistUIData *ctx,
View2D *v2d,
const KeyframeShaderBindings *sh_bindings,
- const ListBase * /*ActKeyColumn*/ keys,
+ const ActKeyColumn *keys,
+ const int key_len,
float ypos,
eSAction_Flag saction_flag)
{
short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE;
- LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
+ for (int i = 0; i < key_len; i++) {
+ const ActKeyColumn *ak = &keys[i];
if (draw_keylist_is_visible_key(v2d, ak)) {
if (ctx->show_ipo) {
handle_type = ak->handle_type;
@@ -469,8 +474,9 @@ static void ED_keylist_draw_list_elem_draw_blocks(AnimKeylistDrawListElem *elem,
DrawKeylistUIData ctx;
draw_keylist_ui_data_init(&ctx, v2d, elem->yscale_fac, elem->channel_locked, elem->saction_flag);
- const ListBase *keys = ED_keylist_listbase(elem->keylist);
- draw_keylist_blocks(&ctx, keys, elem->ypos);
+ const int key_len = ED_keylist_array_len(elem->keylist);
+ const ActKeyColumn *keys = ED_keylist_array(elem->keylist);
+ draw_keylist_blocks(&ctx, keys, key_len, elem->ypos);
}
static void ED_keylist_draw_list_elem_draw_keys(AnimKeylistDrawListElem *elem,
@@ -479,8 +485,15 @@ static void ED_keylist_draw_list_elem_draw_keys(AnimKeylistDrawListElem *elem,
{
DrawKeylistUIData ctx;
draw_keylist_ui_data_init(&ctx, v2d, elem->yscale_fac, elem->channel_locked, elem->saction_flag);
- const ListBase *keys = ED_keylist_listbase(elem->keylist);
- draw_keylist_keys(&ctx, v2d, sh_bindings, keys, elem->ypos, elem->saction_flag);
+
+ const int key_len = ED_keylist_array_len(elem->keylist);
+ const ActKeyColumn *keys = ED_keylist_array(elem->keylist);
+ draw_keylist_keys(&ctx, v2d, sh_bindings, keys, key_len, elem->ypos, elem->saction_flag);
+}
+
+static void ED_keylist_draw_list_elem_prepare_for_drawing(AnimKeylistDrawListElem *elem)
+{
+ ED_keylist_prepare_for_direct_access(elem->keylist);
}
typedef struct AnimKeylistDrawList {
@@ -492,11 +505,25 @@ AnimKeylistDrawList *ED_keylist_draw_list_create(void)
return MEM_callocN(sizeof(AnimKeylistDrawList), __func__);
}
+static void ED_keylist_draw_list_elem_build_task(void *__restrict UNUSED(userdata),
+ void *item,
+ int UNUSED(index),
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ AnimKeylistDrawListElem *elem = item;
+ ED_keylist_draw_list_elem_build_keylist(elem);
+ ED_keylist_draw_list_elem_prepare_for_drawing(elem);
+}
+
static void ED_keylist_draw_list_build_keylists(AnimKeylistDrawList *draw_list)
{
- LISTBASE_FOREACH (AnimKeylistDrawListElem *, elem, &draw_list->channels) {
- ED_keylist_draw_list_elem_build_keylist(elem);
- }
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ /* Create a task per item, a single item is complex enough to deserve its own task. */
+ settings.min_iter_per_thread = 1;
+
+ BLI_task_parallel_listbase(
+ &draw_list->channels, NULL, ED_keylist_draw_list_elem_build_task, &settings);
}
static void ED_keylist_draw_list_draw_blocks(AnimKeylistDrawList *draw_list, View2D *v2d)
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 75ce62d5e27..ec33a42af3b 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -761,11 +761,10 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) {
Object *ob = (Object *)aci->id;
- char *bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones[");
- if (bone_name) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
- MEM_freeN(bone_name);
-
+ bPoseChannel *pchan;
+ char bone_name[sizeof(pchan->name)];
+ if (BLI_str_quoted_substr(aci->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
if (pchan) {
aci->is_bone = true;
}
@@ -824,31 +823,35 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
return 0;
}
-static void flip_names(tAnimCopybufItem *aci, char **name)
+static void flip_names(tAnimCopybufItem *aci, char **r_name)
{
if (aci->is_bone) {
- char *str_start;
- if ((str_start = strstr(aci->rna_path, "pose.bones["))) {
- /* ninja coding, try to change the name */
+ int ofs_start;
+ int ofs_end;
+
+ if (BLI_str_quoted_substr_range(aci->rna_path, "pose.bones[", &ofs_start, &ofs_end)) {
+ char *str_start = aci->rna_path + ofs_start;
+ const char *str_end = aci->rna_path + ofs_end;
+
+ /* Swap out the name.
+ * Note that there is no need to un-escape the string to flip it. */
char bname_new[MAX_VGROUP_NAME];
- char *str_iter, *str_end;
+ char *str_iter;
int length, prefix_l, postfix_l;
- str_start += 12;
prefix_l = str_start - aci->rna_path;
- str_end = strchr(str_start, '\"');
-
length = str_end - str_start;
postfix_l = strlen(str_end);
- /* more ninja stuff, temporary substitute with NULL terminator */
+ /* Temporary substitute with NULL terminator. */
+ BLI_assert(str_start[length] == '\"');
str_start[length] = 0;
BLI_string_flip_side_name(bname_new, str_start, false, sizeof(bname_new));
str_start[length] = '\"';
- str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1),
- "flipped_path");
+ str_iter = *r_name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1),
+ "flipped_path");
BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1);
str_iter += prefix_l;
diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc
index f6ade11a517..c1a18196a3a 100644
--- a/source/blender/editors/animation/keyframes_keylist.cc
+++ b/source/blender/editors/animation/keyframes_keylist.cc
@@ -23,15 +23,20 @@
/* System includes ----------------------------------------------------- */
+#include <algorithm>
#include <cfloat>
#include <cmath>
#include <cstdlib>
#include <cstring>
+#include <functional>
+#include <optional>
#include "MEM_guardedalloc.h"
+#include "BLI_array.hh"
#include "BLI_dlrbTree.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_range.h"
#include "BLI_utildefines.h"
@@ -50,117 +55,294 @@
extern "C" {
/* *************************** Keyframe Processing *************************** */
-struct AnimKeylist {
- DLRBT_Tree keys;
-};
+/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
+
+BLI_INLINE bool is_cfra_eq(const float a, const float b)
+{
+ return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
+}
-static void ED_keylist_init(AnimKeylist *keylist)
+BLI_INLINE bool is_cfra_lt(const float a, const float b)
{
- BLI_dlrbTree_init(&keylist->keys);
+ return (b - a) > BEZT_BINARYSEARCH_THRESH;
}
+/* --------------- */
+
+struct AnimKeylist {
+ /* Number of ActKeyColumn's in the keylist. */
+ size_t column_len = 0;
+
+ bool is_runtime_initialized = false;
+
+ /* Before initializing the runtime, the key_columns list base is used to quickly add columns.
+ * Contains `ActKeyColumn`. Should not be used after runtime is initialized. */
+ ListBase /* ActKeyColumn */ key_columns;
+ /* Last accessed column in the key_columns list base. Inserting columns are typically done in
+ * order. The last accessed column is used as starting point to search for a location to add or
+ * update the next column.*/
+ std::optional<ActKeyColumn *> last_accessed_column = std::nullopt;
+
+ struct {
+ /* When initializing the runtime the columns from the list base `AnimKeyList.key_columns` are
+ * transferred to an array to support binary searching and index based access. */
+ blender::Array<ActKeyColumn> key_columns;
+ /* Wrapper around runtime.key_columns so it can still be accessed as a ListBase. Elements are
+ * owned by runtime.key_columns. */
+ ListBase /* ActKeyColumn */ list_wrapper;
+ } runtime;
+
+ AnimKeylist()
+ {
+ BLI_listbase_clear(&this->key_columns);
+ BLI_listbase_clear(&this->runtime.list_wrapper);
+ }
+
+ ~AnimKeylist()
+ {
+ BLI_freelistN(&this->key_columns);
+ BLI_listbase_clear(&this->runtime.list_wrapper);
+ }
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("editors:AnimKeylist")
+#endif
+};
+
AnimKeylist *ED_keylist_create(void)
{
- AnimKeylist *keylist = static_cast<AnimKeylist *>(MEM_callocN(sizeof(AnimKeylist), __func__));
- ED_keylist_init(keylist);
+ AnimKeylist *keylist = new AnimKeylist();
return keylist;
}
void ED_keylist_free(AnimKeylist *keylist)
{
BLI_assert(keylist);
- BLI_dlrbTree_free(&keylist->keys);
- MEM_freeN(keylist);
+ delete keylist;
}
-const ActKeyColumn *ED_keylist_find_exact(const AnimKeylist *keylist, float cfra)
+static void ED_keylist_convert_key_columns_to_array(AnimKeylist *keylist)
{
- return (const ActKeyColumn *)BLI_dlrbTree_search_exact(
- &keylist->keys, compare_ak_cfraPtr, &cfra);
+ size_t index;
+ LISTBASE_FOREACH_INDEX (ActKeyColumn *, key, &keylist->key_columns, index) {
+ keylist->runtime.key_columns[index] = *key;
+ }
}
-const ActKeyColumn *ED_keylist_find_next(const AnimKeylist *keylist, float cfra)
+static void ED_keylist_runtime_update_key_column_next_prev(AnimKeylist *keylist)
{
- return (const ActKeyColumn *)BLI_dlrbTree_search_next(&keylist->keys, compare_ak_cfraPtr, &cfra);
+ for (size_t index = 0; index < keylist->column_len; index++) {
+ const bool is_first = (index == 0);
+ keylist->runtime.key_columns[index].prev = is_first ? nullptr :
+ &keylist->runtime.key_columns[index - 1];
+ const bool is_last = (index == keylist->column_len - 1);
+ keylist->runtime.key_columns[index].next = is_last ? nullptr :
+ &keylist->runtime.key_columns[index + 1];
+ }
}
-const ActKeyColumn *ED_keylist_find_prev(const AnimKeylist *keylist, float cfra)
+static void ED_keylist_runtime_init_listbase(AnimKeylist *keylist)
{
- return (const ActKeyColumn *)BLI_dlrbTree_search_prev(&keylist->keys, compare_ak_cfraPtr, &cfra);
+ if (ED_keylist_is_empty(keylist)) {
+ BLI_listbase_clear(&keylist->runtime.list_wrapper);
+ return;
+ }
+
+ keylist->runtime.list_wrapper.first = &keylist->runtime.key_columns[0];
+ keylist->runtime.list_wrapper.last = &keylist->runtime.key_columns[keylist->column_len - 1];
}
-/* TODO(jbakker): Should we change this to use `ED_keylist_find_next(keys, min_fra)` and only check
- * boundary of `max_fra`. */
-const ActKeyColumn *ED_keylist_find_any_between(const AnimKeylist *keylist,
- const Range2f frame_range)
+static void ED_keylist_runtime_init(AnimKeylist *keylist)
{
- for (const ActKeyColumn *ak = static_cast<const ActKeyColumn *>(keylist->keys.root); ak;
- ak = static_cast<const ActKeyColumn *>((ak->cfra < frame_range.min) ? ak->right :
- ak->left)) {
- if (range2f_in_range(&frame_range, ak->cfra)) {
- return ak;
- }
+ BLI_assert(!keylist->is_runtime_initialized);
+
+ keylist->runtime.key_columns = blender::Array<ActKeyColumn>(keylist->column_len);
+
+ /* Convert linked list to array to support fast searching. */
+ ED_keylist_convert_key_columns_to_array(keylist);
+ /* Ensure that the array can also be used as a listbase for external usages. */
+ ED_keylist_runtime_update_key_column_next_prev(keylist);
+ ED_keylist_runtime_init_listbase(keylist);
+
+ keylist->is_runtime_initialized = true;
+}
+
+static void ED_keylist_reset_last_accessed(AnimKeylist *keylist)
+{
+ BLI_assert(!keylist->is_runtime_initialized);
+ keylist->last_accessed_column.reset();
+}
+
+void ED_keylist_prepare_for_direct_access(AnimKeylist *keylist)
+{
+ if (keylist->is_runtime_initialized) {
+ return;
+ }
+ ED_keylist_runtime_init(keylist);
+}
+
+static const ActKeyColumn *ED_keylist_find_lower_bound(const AnimKeylist *keylist,
+ const float cfra)
+{
+ BLI_assert(!ED_keylist_is_empty(keylist));
+ const ActKeyColumn *begin = std::begin(keylist->runtime.key_columns);
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ ActKeyColumn value;
+ value.cfra = cfra;
+
+ const ActKeyColumn *found_column = std::lower_bound(
+ begin, end, value, [](const ActKeyColumn &column, const ActKeyColumn &other) {
+ return is_cfra_lt(column.cfra, other.cfra);
+ });
+ return found_column;
+}
+
+static const ActKeyColumn *ED_keylist_find_upper_bound(const AnimKeylist *keylist,
+ const float cfra)
+{
+ BLI_assert(!ED_keylist_is_empty(keylist));
+ const ActKeyColumn *begin = std::begin(keylist->runtime.key_columns);
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ ActKeyColumn value;
+ value.cfra = cfra;
+
+ const ActKeyColumn *found_column = std::upper_bound(
+ begin, end, value, [](const ActKeyColumn &column, const ActKeyColumn &other) {
+ return is_cfra_lt(column.cfra, other.cfra);
+ });
+ return found_column;
+}
+
+const ActKeyColumn *ED_keylist_find_exact(const AnimKeylist *keylist, const float cfra)
+{
+ BLI_assert_msg(keylist->is_runtime_initialized,
+ "ED_keylist_prepare_for_direct_access needs to be called before searching.");
+
+ if (ED_keylist_is_empty(keylist)) {
+ return nullptr;
+ }
+
+ const ActKeyColumn *found_column = ED_keylist_find_lower_bound(keylist, cfra);
+
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ if (found_column == end) {
+ return nullptr;
+ }
+ if (is_cfra_eq(found_column->cfra, cfra)) {
+ return found_column;
}
return nullptr;
}
-bool ED_keylist_is_empty(const struct AnimKeylist *keylist)
+const ActKeyColumn *ED_keylist_find_next(const AnimKeylist *keylist, const float cfra)
{
- return keylist->keys.root == nullptr;
+ BLI_assert_msg(keylist->is_runtime_initialized,
+ "ED_keylist_prepare_for_direct_access needs to be called before searching.");
+
+ if (ED_keylist_is_empty(keylist)) {
+ return nullptr;
+ }
+
+ const ActKeyColumn *found_column = ED_keylist_find_upper_bound(keylist, cfra);
+
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ if (found_column == end) {
+ return nullptr;
+ }
+ return found_column;
}
-const struct ListBase *ED_keylist_listbase(const AnimKeylist *keylist)
+const ActKeyColumn *ED_keylist_find_prev(const AnimKeylist *keylist, const float cfra)
{
- return (ListBase *)&keylist->keys;
+ BLI_assert_msg(keylist->is_runtime_initialized,
+ "ED_keylist_prepare_for_direct_access needs to be called before searching.");
+
+ if (ED_keylist_is_empty(keylist)) {
+ return nullptr;
+ }
+
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ const ActKeyColumn *found_column = ED_keylist_find_lower_bound(keylist, cfra);
+
+ if (found_column == end) {
+ /* Nothing found, return the last item. */
+ return end - 1;
+ }
+
+ const ActKeyColumn *prev_column = found_column->prev;
+ return prev_column;
}
-bool ED_keylist_frame_range(const struct AnimKeylist *keylist, Range2f *r_frame_range)
+const ActKeyColumn *ED_keylist_find_any_between(const AnimKeylist *keylist,
+ const Range2f frame_range)
{
- BLI_assert(r_frame_range);
+ BLI_assert_msg(keylist->is_runtime_initialized,
+ "ED_keylist_prepare_for_direct_access needs to be called before searching.");
if (ED_keylist_is_empty(keylist)) {
- return false;
+ return nullptr;
}
- const ActKeyColumn *first_column = (const ActKeyColumn *)keylist->keys.first;
- r_frame_range->min = first_column->cfra;
+ const ActKeyColumn *column = ED_keylist_find_lower_bound(keylist, frame_range.min);
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ if (column == end) {
+ return nullptr;
+ }
+ if (column->cfra >= frame_range.max) {
+ return nullptr;
+ }
+ return column;
+}
- const ActKeyColumn *last_column = (const ActKeyColumn *)keylist->keys.last;
- r_frame_range->max = last_column->cfra;
+const ActKeyColumn *ED_keylist_array(const struct AnimKeylist *keylist)
+{
+ BLI_assert_msg(
+ keylist->is_runtime_initialized,
+ "ED_keylist_prepare_for_direct_access needs to be called before accessing array.");
+ return keylist->runtime.key_columns.data();
+}
- return true;
+int64_t ED_keylist_array_len(const struct AnimKeylist *keylist)
+{
+ return keylist->column_len;
}
-/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
-BLI_INLINE bool is_cfra_eq(const float a, const float b)
+bool ED_keylist_is_empty(const struct AnimKeylist *keylist)
{
- return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
+ return keylist->column_len == 0;
}
-BLI_INLINE bool is_cfra_lt(const float a, const float b)
+const struct ListBase *ED_keylist_listbase(const AnimKeylist *keylist)
{
- return (b - a) > BEZT_BINARYSEARCH_THRESH;
+ if (keylist->is_runtime_initialized) {
+ return &keylist->runtime.list_wrapper;
+ }
+ return &keylist->key_columns;
}
-/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
-/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
-short compare_ak_cfraPtr(void *node, void *data)
+bool ED_keylist_frame_range(const struct AnimKeylist *keylist, Range2f *r_frame_range)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- const float *cframe = static_cast<const float *>(data);
- const float val = *cframe;
+ BLI_assert(r_frame_range);
- if (is_cfra_eq(val, ak->cfra)) {
- return 0;
+ if (ED_keylist_is_empty(keylist)) {
+ return false;
}
- if (val < ak->cfra) {
- return -1;
+ const ActKeyColumn *first_column;
+ const ActKeyColumn *last_column;
+ if (keylist->is_runtime_initialized) {
+ first_column = &keylist->runtime.key_columns[0];
+ last_column = &keylist->runtime.key_columns[keylist->column_len - 1];
}
- return 1;
-}
+ else {
+ first_column = static_cast<const ActKeyColumn *>(keylist->key_columns.first);
+ last_column = static_cast<const ActKeyColumn *>(keylist->key_columns.last);
+ }
+ r_frame_range->min = first_column->cfra;
+ r_frame_range->max = last_column->cfra;
-/* --------------- */
+ return true;
+}
/* Set of references to three logically adjacent keys. */
struct BezTripleChain {
@@ -243,16 +425,8 @@ static eKeyframeExtremeDrawOpts bezt_extreme_type(const BezTripleChain *chain)
return KEYFRAME_EXTREME_NONE;
}
-/* Comparator callback used for ActKeyColumns and BezTripleChain */
-static short compare_ak_bezt(void *node, void *data)
-{
- BezTripleChain *chain = static_cast<BezTripleChain *>(data);
-
- return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]);
-}
-
/* New node callback used for building ActKeyColumns from BezTripleChain */
-static DLRBT_Node *nalloc_ak_bezt(void *data)
+static ActKeyColumn *nalloc_ak_bezt(void *data)
{
ActKeyColumn *ak = static_cast<ActKeyColumn *>(
MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn"));
@@ -269,13 +443,12 @@ static DLRBT_Node *nalloc_ak_bezt(void *data)
/* count keyframes in this column */
ak->totkey = 1;
- return (DLRBT_Node *)ak;
+ return ak;
}
/* Node updater callback used for building ActKeyColumns from BezTripleChain */
-static void nupdate_ak_bezt(void *node, void *data)
+static void nupdate_ak_bezt(ActKeyColumn *ak, void *data)
{
- ActKeyColumn *ak = static_cast<ActKeyColumn *>(node);
const BezTripleChain *chain = static_cast<const BezTripleChain *>(data);
const BezTriple *bezt = chain->cur;
@@ -312,17 +485,8 @@ static void nupdate_ak_bezt(void *node, void *data)
/* ......... */
-/* Comparator callback used for ActKeyColumns and GPencil frame */
-static short compare_ak_gpframe(void *node, void *data)
-{
- const bGPDframe *gpf = (bGPDframe *)data;
-
- float frame = gpf->framenum;
- return compare_ak_cfraPtr(node, &frame);
-}
-
/* New node callback used for building ActKeyColumns from GPencil frames */
-static DLRBT_Node *nalloc_ak_gpframe(void *data)
+static ActKeyColumn *nalloc_ak_gpframe(void *data)
{
ActKeyColumn *ak = static_cast<ActKeyColumn *>(
MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"));
@@ -340,14 +504,13 @@ static DLRBT_Node *nalloc_ak_gpframe(void *data)
ak->block.sel = ak->sel;
ak->block.flag |= ACTKEYBLOCK_FLAG_GPENCIL;
- return (DLRBT_Node *)ak;
+ return ak;
}
/* Node updater callback used for building ActKeyColumns from GPencil frames */
-static void nupdate_ak_gpframe(void *node, void *data)
+static void nupdate_ak_gpframe(ActKeyColumn *ak, void *data)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- const bGPDframe *gpf = (bGPDframe *)data;
+ bGPDframe *gpf = (bGPDframe *)data;
/* set selection status and 'touched' status */
if (gpf->flag & GP_FRAME_SELECT) {
@@ -366,17 +529,8 @@ static void nupdate_ak_gpframe(void *node, void *data)
/* ......... */
-/* Comparator callback used for ActKeyColumns and GPencil frame */
-static short compare_ak_masklayshape(void *node, void *data)
-{
- const MaskLayerShape *masklay_shape = (const MaskLayerShape *)data;
-
- float frame = masklay_shape->frame;
- return compare_ak_cfraPtr(node, &frame);
-}
-
/* New node callback used for building ActKeyColumns from GPencil frames */
-static DLRBT_Node *nalloc_ak_masklayshape(void *data)
+static ActKeyColumn *nalloc_ak_masklayshape(void *data)
{
ActKeyColumn *ak = static_cast<ActKeyColumn *>(
MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"));
@@ -389,14 +543,13 @@ static DLRBT_Node *nalloc_ak_masklayshape(void *data)
/* count keyframes in this column */
ak->totkey = 1;
- return (DLRBT_Node *)ak;
+ return ak;
}
/* Node updater callback used for building ActKeyColumns from GPencil frames */
-static void nupdate_ak_masklayshape(void *node, void *data)
+static void nupdate_ak_masklayshape(ActKeyColumn *ak, void *data)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- const MaskLayerShape *masklay_shape = (const MaskLayerShape *)data;
+ MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
/* set selection status and 'touched' status */
if (masklay_shape->flag & MASK_SHAPE_SELECT) {
@@ -408,6 +561,95 @@ static void nupdate_ak_masklayshape(void *node, void *data)
}
/* --------------- */
+using KeylistCreateColumnFunction = std::function<ActKeyColumn *(void *userdata)>;
+using KeylistUpdateColumnFunction = std::function<void(ActKeyColumn *, void *)>;
+
+/* `ED_keylist_find_neighbour_front_to_back` is called before the runtime can be initialized so we
+ * cannot use bin searching. */
+static ActKeyColumn *ED_keylist_find_neighbour_front_to_back(ActKeyColumn *cursor, float cfra)
+{
+ while (cursor->next && cursor->next->cfra <= cfra) {
+ cursor = cursor->next;
+ }
+ return cursor;
+}
+
+/* `ED_keylist_find_neighbour_back_to_front` is called before the runtime can be initialized so we
+ * cannot use bin searching. */
+static ActKeyColumn *ED_keylist_find_neighbour_back_to_front(ActKeyColumn *cursor, float cfra)
+{
+ while (cursor->prev && cursor->prev->cfra >= cfra) {
+ cursor = cursor->prev;
+ }
+ return cursor;
+}
+
+/*
+ * `ED_keylist_find_exact_or_neighbour_column` is called before the runtime can be initialized so
+ * we cannot use bin searching.
+ *
+ * This function is called to add or update columns in the keylist.
+ * Typically columns are sorted by frame number so keeping track of the last_accessed_column
+ * reduces searching.
+ */
+static ActKeyColumn *ED_keylist_find_exact_or_neighbour_column(AnimKeylist *keylist, float cfra)
+{
+ BLI_assert(!keylist->is_runtime_initialized);
+ if (ED_keylist_is_empty(keylist)) {
+ return nullptr;
+ }
+
+ ActKeyColumn *cursor = keylist->last_accessed_column.value_or(
+ static_cast<ActKeyColumn *>(keylist->key_columns.first));
+ if (!is_cfra_eq(cursor->cfra, cfra)) {
+ const bool walking_direction_front_to_back = cursor->cfra <= cfra;
+ if (walking_direction_front_to_back) {
+ cursor = ED_keylist_find_neighbour_front_to_back(cursor, cfra);
+ }
+ else {
+ cursor = ED_keylist_find_neighbour_back_to_front(cursor, cfra);
+ }
+ }
+
+ keylist->last_accessed_column = cursor;
+ return cursor;
+}
+
+static void ED_keylist_add_or_update_column(AnimKeylist *keylist,
+ float cfra,
+ KeylistCreateColumnFunction create_func,
+ KeylistUpdateColumnFunction update_func,
+ void *userdata)
+{
+ BLI_assert_msg(
+ !keylist->is_runtime_initialized,
+ "Modifying AnimKeylist isn't allowed after runtime is initialized "
+ "keylist->key_columns/columns_len will get out of sync with runtime.key_columns.");
+ if (ED_keylist_is_empty(keylist)) {
+ ActKeyColumn *key_column = create_func(userdata);
+ BLI_addhead(&keylist->key_columns, key_column);
+ keylist->column_len += 1;
+ keylist->last_accessed_column = key_column;
+ return;
+ }
+
+ ActKeyColumn *nearest = ED_keylist_find_exact_or_neighbour_column(keylist, cfra);
+ if (is_cfra_eq(nearest->cfra, cfra)) {
+ update_func(nearest, userdata);
+ }
+ else if (is_cfra_lt(nearest->cfra, cfra)) {
+ ActKeyColumn *key_column = create_func(userdata);
+ BLI_insertlinkafter(&keylist->key_columns, nearest, key_column);
+ keylist->column_len += 1;
+ keylist->last_accessed_column = key_column;
+ }
+ else {
+ ActKeyColumn *key_column = create_func(userdata);
+ BLI_insertlinkbefore(&keylist->key_columns, nearest, key_column);
+ keylist->column_len += 1;
+ keylist->last_accessed_column = key_column;
+ }
+}
/* Add the given BezTriple to the given 'list' of Keyframes */
static void add_bezt_to_keycolumns_list(AnimKeylist *keylist, BezTripleChain *bezt)
@@ -416,7 +658,8 @@ static void add_bezt_to_keycolumns_list(AnimKeylist *keylist, BezTripleChain *be
return;
}
- BLI_dlrbTree_add(&keylist->keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt);
+ float cfra = bezt->cur->vec[1][0];
+ ED_keylist_add_or_update_column(keylist, cfra, nalloc_ak_bezt, nupdate_ak_bezt, bezt);
}
/* Add the given GPencil Frame to the given 'list' of Keyframes */
@@ -426,7 +669,8 @@ static void add_gpframe_to_keycolumns_list(AnimKeylist *keylist, bGPDframe *gpf)
return;
}
- BLI_dlrbTree_add(&keylist->keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf);
+ float cfra = gpf->framenum;
+ ED_keylist_add_or_update_column(keylist, cfra, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf);
}
/* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */
@@ -436,11 +680,9 @@ static void add_masklay_to_keycolumns_list(AnimKeylist *keylist, MaskLayerShape
return;
}
- BLI_dlrbTree_add(&keylist->keys,
- compare_ak_masklayshape,
- nalloc_ak_masklayshape,
- nupdate_ak_masklayshape,
- masklay_shape);
+ float cfra = masklay_shape->frame;
+ ED_keylist_add_or_update_column(
+ keylist, cfra, nalloc_ak_masklayshape, nupdate_ak_masklayshape, masklay_shape);
}
/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
@@ -476,7 +718,7 @@ static void compute_keyblock_data(ActKeyBlockInfo *info,
hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) &&
IS_EQF(prev->vec[1][1], prev->vec[2][1]);
}
- /* This interpolation type induces movement even between identical keys. */
+ /* This interpolation type induces movement even between identical columns. */
else {
hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC);
}
@@ -514,7 +756,7 @@ static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block)
static void add_bezt_to_keyblocks_list(AnimKeylist *keylist, BezTriple *bezt, const int bezt_len)
{
- ActKeyColumn *col = static_cast<ActKeyColumn *>(keylist->keys.first);
+ ActKeyColumn *col = static_cast<ActKeyColumn *>(keylist->key_columns.first);
if (bezt && bezt_len >= 2) {
ActKeyBlockInfo block;
@@ -532,19 +774,15 @@ static void add_bezt_to_keyblocks_list(AnimKeylist *keylist, BezTriple *bezt, co
if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
/* Backtrack to find the right location. */
if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
- ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact(
- &keylist->keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]);
+ ActKeyColumn *newcol = ED_keylist_find_exact_or_neighbour_column(keylist, col->cfra);
- if (newcol != nullptr) {
- col = newcol;
+ BLI_assert(newcol);
+ BLI_assert(newcol->cfra == col->cfra);
- /* The previous keyblock is garbage too. */
- if (col->prev != nullptr) {
- add_keyblock_info(col->prev, &dummy_keyblock);
- }
- }
- else {
- BLI_assert(false);
+ col = newcol;
+ /* The previous keyblock is garbage too. */
+ if (col->prev != nullptr) {
+ add_keyblock_info(col->prev, &dummy_keyblock);
}
}
@@ -577,20 +815,17 @@ static void add_bezt_to_keyblocks_list(AnimKeylist *keylist, BezTriple *bezt, co
*/
static void update_keyblocks(AnimKeylist *keylist, BezTriple *bezt, const int bezt_len)
{
- /* Recompute the prev/next linked list. */
- BLI_dlrbTree_linkedlist_sync(&keylist->keys);
-
/* Find the curve count */
int max_curve = 0;
- LISTBASE_FOREACH (ActKeyColumn *, col, &keylist->keys) {
+ LISTBASE_FOREACH (ActKeyColumn *, col, &keylist->key_columns) {
max_curve = MAX2(max_curve, col->totcurve);
}
/* Propagate blocks to inserted keys */
ActKeyColumn *prev_ready = nullptr;
- LISTBASE_FOREACH (ActKeyColumn *, col, &keylist->keys) {
+ LISTBASE_FOREACH (ActKeyColumn *, col, &keylist->key_columns) {
/* Pre-existing column. */
if (col->totcurve > 0) {
prev_ready = col;
@@ -775,6 +1010,7 @@ void cachefile_to_keylist(bDopeSheet *ads,
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, AnimKeylist *keylist, const int saction_flag)
{
if (fcu && fcu->totvert && fcu->bezt) {
+ ED_keylist_reset_last_accessed(keylist);
/* apply NLA-mapping (if applicable) */
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, fcu, false, false);
@@ -790,7 +1026,7 @@ void fcurve_to_keylist(AnimData *adt, FCurve *fcu, AnimKeylist *keylist, const i
for (int v = 0; v < fcu->totvert; v++) {
chain.cur = &fcu->bezt[v];
- /* Neighbor keys, accounting for being cyclic. */
+ /* Neighbor columns, accounting for being cyclic. */
if (do_extremes) {
chain.prev = (v > 0) ? &fcu->bezt[v - 1] :
is_cyclic ? &fcu->bezt[fcu->totvert - 2] :
@@ -856,6 +1092,7 @@ void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, AnimKeylist *keylist, con
void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, AnimKeylist *keylist)
{
if (gpl && keylist) {
+ ED_keylist_reset_last_accessed(keylist);
/* Although the frames should already be in an ordered list,
* they are not suitable for displaying yet. */
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
@@ -869,6 +1106,7 @@ void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, AnimKeylist *keylis
void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, AnimKeylist *keylist)
{
if (masklay && keylist) {
+ ED_keylist_reset_last_accessed(keylist);
LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
add_masklay_to_keycolumns_list(keylist, masklay_shape);
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 0a499232ba9..8dc4aed9f0e 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -2216,14 +2216,13 @@ static int clear_anim_v3d_exec(bContext *C, wmOperator *UNUSED(op))
/* in pose mode, only delete the F-Curve if it belongs to a selected bone */
if (ob->mode & OB_MODE_POSE) {
- if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones[")) {
-
- /* get bone-name, and check if this bone is selected */
- char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
- if (bone_name) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
- MEM_freeN(bone_name);
-
+ if (fcu->rna_path) {
+ /* Get bone-name, and check if this bone is selected. */
+ bPoseChannel *pchan = NULL;
+ char bone_name[sizeof(pchan->name)];
+ if (BLI_str_quoted_substr(
+ fcu->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
/* Delete if bone is selected. */
if ((pchan) && (pchan->bone)) {
if (pchan->bone->flag & BONE_SELECTED) {
@@ -2320,15 +2319,15 @@ static int delete_key_v3d_without_keying_set(bContext *C, wmOperator *op)
* NOTE: This is only done in pose mode.
* In object mode, we're dealing with the entire object.
*/
- if ((ob->mode & OB_MODE_POSE) && strstr(fcu->rna_path, "pose.bones[\"")) {
+ if (ob->mode & OB_MODE_POSE) {
bPoseChannel *pchan = NULL;
- /* get bone-name, and check if this bone is selected */
- char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
- if (bone_name) {
- pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
- MEM_freeN(bone_name);
+ /* Get bone-name, and check if this bone is selected. */
+ char bone_name[sizeof(pchan->name)];
+ if (!BLI_str_quoted_substr(fcu->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
+ continue;
}
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
/* skip if bone is not selected */
if ((pchan) && (pchan->bone)) {
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 45bf18fe1bb..21a5c6c2865 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -259,7 +259,7 @@ static int armature_click_extrude_invoke(bContext *C, wmOperator *op, const wmEv
void ARMATURE_OT_click_extrude(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Click-Extrude";
+ ot->name = "Extrude to Cursor";
ot->idname = "ARMATURE_OT_click_extrude";
ot->description = "Create a new bone going from the last selected joint to the mouse position";
@@ -269,7 +269,7 @@ void ARMATURE_OT_click_extrude(wmOperatorType *ot)
ot->poll = ED_operator_editarmature;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* props */
}
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 1dbb859fd6c..e5b8983af93 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -1106,20 +1106,18 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, bool ex
for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
/* only items related to this object will be relevant */
if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
- if (strstr(ksp->rna_path, "bones")) {
- char *boneName = BLI_str_quoted_substrN(ksp->rna_path, "bones[");
-
- if (boneName) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
- MEM_freeN(boneName);
-
- if (pchan) {
- /* select if bone is visible and can be affected */
- if (PBONE_SELECTABLE(arm, pchan->bone)) {
- pchan->bone->flag |= BONE_SELECTED;
- changed = true;
- }
- }
+ bPoseChannel *pchan = NULL;
+ char boneName[sizeof(pchan->name)];
+ if (!BLI_str_quoted_substr(ksp->rna_path, "bones[", boneName, sizeof(boneName))) {
+ continue;
+ }
+ pchan = BKE_pose_channel_find_name(pose, boneName);
+
+ if (pchan) {
+ /* select if bone is visible and can be affected */
+ if (PBONE_SELECTABLE(arm, pchan->bone)) {
+ pchan->bone->flag |= BONE_SELECTED;
+ changed = true;
}
}
}
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index bc5cbd92deb..f23376867af 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -976,6 +976,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, const wmEvent *
}
/* Cancel if no keyframes found. */
+ ED_keylist_prepare_for_direct_access(pso->keylist);
if (ED_keylist_is_empty(pso->keylist)) {
BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
pose_slide_exit(C, op);
@@ -1267,6 +1268,8 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Perform pose updates - in response to some user action
* (e.g. pressing a key or moving the mouse). */
if (do_pose_update) {
+ RNA_float_set(op->ptr, "factor", ED_slider_factor_get(pso->slider));
+
/* Update percentage indicator in header. */
pose_slide_draw_status(C, pso);
@@ -1712,6 +1715,7 @@ static float pose_propagate_get_boneHoldEndFrame(tPChanFCurveLink *pfl, float st
FCurve *fcu = (FCurve *)ld->data;
fcurve_to_keylist(adt, fcu, keylist, 0);
}
+ ED_keylist_prepare_for_direct_access(keylist);
/* Find the long keyframe (i.e. hold), and hence obtain the endFrame value
* - the best case would be one that starts on the frame itself
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index c399abfa52d..9b43e23bd32 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -5620,7 +5620,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void CURVE_OT_vertex_add(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Vertex";
+ ot->name = "Extrude to Cursor or Add";
ot->idname = "CURVE_OT_vertex_add";
ot->description = "Add a new control point (linked to only selected end-curve one, if any)";
@@ -5630,7 +5630,7 @@ void CURVE_OT_vertex_add(wmOperatorType *ot)
ot->poll = ED_operator_editcurve;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
RNA_def_float_vector_xyz(ot->srna,
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index d1fe162fc4a..75fb17e8cc1 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -515,7 +515,6 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
bool newob = false;
bool enter_editmode;
ushort local_view_bits;
- float dia;
float loc[3], rot[3];
float mat[4][4];
@@ -535,7 +534,6 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
newob = true;
cu = (Curve *)obedit->data;
- cu->flag |= CU_DEFORM_FILL;
if (type & CU_PRIM_PATH) {
cu->flag |= CU_PATH | CU_3D;
@@ -556,9 +554,10 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
}
}
- ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
- dia = RNA_float_get(op->ptr, "radius");
- mul_mat3_m4_fl(mat, dia);
+ float radius = RNA_float_get(op->ptr, "radius");
+ float scale[3];
+ copy_v3_fl(scale, radius);
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, scale, mat);
nu = ED_curve_add_nurbs_primitive(C, obedit, mat, type, newob);
editnurb = object_editcurve_get(obedit);
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index c4916b9182f..702fd2e375a 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -336,6 +336,7 @@ set(ICON_NAMES
lightprobe_cubemap
lightprobe_planar
lightprobe_grid
+ mod_dash
color_red
color_green
color_blue
@@ -390,6 +391,9 @@ set(ICON_NAMES
small_caps
modifier
con_action
+ mod_length
+ mod_dash
+ mod_lineart
holdout_off
holdout_on
indirect_only_off
diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt
index eeb1e60166b..bfe8334b390 100644
--- a/source/blender/editors/gizmo_library/CMakeLists.txt
+++ b/source/blender/editors/gizmo_library/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/clog
../../../../intern/eigen
../../../../intern/glew-mx
../../../../intern/guardedalloc
diff --git a/source/blender/editors/gizmo_library/gizmo_library_utils.c b/source/blender/editors/gizmo_library/gizmo_library_utils.c
index 7d0ae5afb9b..a0db2a8e627 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_library_utils.c
@@ -39,9 +39,13 @@
#include "ED_view3d.h"
+#include "CLG_log.h"
+
/* own includes */
#include "gizmo_library_intern.h"
+static CLG_LogRef LOG = {"ed.gizmo.library_utils"};
+
/* factor for precision tweaking */
#define GIZMO_PRECISION_FAC 0.05f
@@ -182,7 +186,7 @@ bool gizmo_window_project_2d(bContext *C,
bool use_offset,
float r_co[2])
{
- float mat[4][4];
+ float mat[4][4], imat[4][4];
{
float mat_identity[4][4];
struct WM_GizmoMatrixParams params = {NULL};
@@ -193,6 +197,14 @@ bool gizmo_window_project_2d(bContext *C,
WM_gizmo_calc_matrix_final_params(gz, &params, mat);
}
+ if (!invert_m4_m4(imat, mat)) {
+ CLOG_WARN(&LOG,
+ "Gizmo \"%s\" of group \"%s\" has matrix that could not be inverted "
+ "(projection will fail)",
+ gz->type->idname,
+ gz->parent_gzgroup->type->idname);
+ }
+
/* rotate mouse in relation to the center and relocate it */
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
/* For 3d views, transform 2D mouse pos onto plane. */
@@ -202,8 +214,6 @@ bool gizmo_window_project_2d(bContext *C,
plane_from_point_normal_v3(plane, mat[3], mat[2]);
bool clip_ray = ((RegionView3D *)region->regiondata)->is_persp;
if (ED_view3d_win_to_3d_on_plane(region, plane, mval, clip_ray, co)) {
- float imat[4][4];
- invert_m4_m4(imat, mat);
mul_m4_v3(imat, co);
r_co[0] = co[(axis + 1) % 3];
r_co[1] = co[(axis + 2) % 3];
@@ -213,8 +223,6 @@ bool gizmo_window_project_2d(bContext *C,
}
float co[3] = {mval[0], mval[1], 0.0f};
- float imat[4][4];
- invert_m4_m4(imat, mat);
mul_m4_v3(imat, co);
copy_v2_v2(r_co, co);
return true;
@@ -223,7 +231,7 @@ bool gizmo_window_project_2d(bContext *C,
bool gizmo_window_project_3d(
bContext *C, const struct wmGizmo *gz, const float mval[2], bool use_offset, float r_co[3])
{
- float mat[4][4];
+ float mat[4][4], imat[4][4];
{
float mat_identity[4][4];
struct WM_GizmoMatrixParams params = {NULL};
@@ -234,20 +242,25 @@ bool gizmo_window_project_3d(
WM_gizmo_calc_matrix_final_params(gz, &params, mat);
}
+ if (!invert_m4_m4(imat, mat)) {
+ CLOG_WARN(&LOG,
+ "Gizmo \"%s\" of group \"%s\" has matrix that could not be inverted "
+ "(projection will fail)",
+ gz->type->idname,
+ gz->parent_gzgroup->type->idname);
+ }
+
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
/* NOTE: we might want a custom reference point passed in,
* instead of the gizmo center. */
ED_view3d_win_to_3d(v3d, region, mat[3], mval, r_co);
- invert_m4(mat);
- mul_m4_v3(mat, r_co);
+ mul_m4_v3(imat, r_co);
return true;
}
float co[3] = {mval[0], mval[1], 0.0f};
- float imat[4][4];
- invert_m4_m4(imat, mat);
mul_m4_v3(imat, co);
copy_v2_v2(r_co, co);
return true;
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index bf47704746b..65c5b8ee573 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -2423,7 +2423,7 @@ static void annotation_add_missing_events(bContext *C,
static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p = op->customdata;
- /* default exit state - pass through to support MMB view nav, etc. */
+ /* Default exit state - pass through to support MMB view navigation, etc. */
int estate = OPERATOR_PASS_THROUGH;
/* NOTE(mike erwin): Not quite what I was looking for, but a good start!
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 8baac26bed3..a77d3bee025 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -1347,6 +1347,8 @@ static int gpencil_merge_layer_exec(bContext *C, wmOperator *op)
bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum));
if (!gpf_dst) {
gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY);
+ /* Use same frame type. */
+ gpf_dst->key_type = gpf_src->key_type;
BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 8d1f841da6c..75ddfa47c57 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -3618,7 +3618,7 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op)
}
elem = &strokes_list[i];
/* Join new_stroke and stroke B. */
- BKE_gpencil_stroke_join(gps_new, elem->gps, leave_gaps, true);
+ BKE_gpencil_stroke_join(gps_new, elem->gps, leave_gaps, true, false);
elem->used = true;
}
@@ -3967,7 +3967,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
/* perform smoothing */
if (smooth_position) {
- BKE_gpencil_stroke_smooth(gps, i, factor);
+ BKE_gpencil_stroke_smooth_point(gps, i, factor);
}
if (smooth_strength) {
BKE_gpencil_stroke_smooth_strength(gps, i, factor);
@@ -5243,7 +5243,7 @@ void GPENCIL_OT_stroke_cutter(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flag */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 0c88d678ef4..f5474a7cdc3 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1569,7 +1569,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
float smoothfac = 1.0f;
for (int r = 0; r < 1; r++) {
for (int i = 0; i < gps->totpoints; i++) {
- BKE_gpencil_stroke_smooth(gps, i, smoothfac - reduce);
+ BKE_gpencil_stroke_smooth_point(gps, i, smoothfac - reduce);
}
reduce += 0.25f; /* reduce the factor */
}
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index a8bd3b11bb1..fdd9f44605e 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -333,7 +333,7 @@ static void gpencil_interpolate_smooth_stroke(bGPDstroke *gps,
float reduce = 0.0f;
for (int r = 0; r < smooth_steps; r++) {
for (int i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth(gps, i, smooth_factor - reduce);
+ BKE_gpencil_stroke_smooth_point(gps, i, smooth_factor - reduce);
BKE_gpencil_stroke_smooth_strength(gps, i, smooth_factor);
}
reduce += 0.25f; /* reduce the factor */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index d2dbf6ab2a6..9b157224178 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1209,7 +1209,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
float reduce = 0.0f;
for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) {
for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth(gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
+ BKE_gpencil_stroke_smooth_point(
+ gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
BKE_gpencil_stroke_smooth_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
}
reduce += 0.25f; /* reduce the factor */
@@ -1221,7 +1222,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
float ifac = (float)brush->gpencil_settings->input_samples / 10.0f;
float sfac = interpf(1.0f, 0.2f, ifac);
for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth(gps, i, sfac);
+ BKE_gpencil_stroke_smooth_point(gps, i, sfac);
BKE_gpencil_stroke_smooth_strength(gps, i, sfac);
}
}
@@ -1288,11 +1289,23 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* Join with existing strokes. */
if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) {
if (gps->prev != NULL) {
+ BKE_gpencil_stroke_boundingbox_calc(gps);
+ float diff_mat[4][4], ctrl1[2], ctrl2[2];
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, p->ob, gpl, diff_mat);
+ ED_gpencil_stroke_extremes_to2d(&p->gsc, diff_mat, gps, ctrl1, ctrl2);
+
int pt_index = 0;
bool doit = true;
while (doit && gps) {
- bGPDstroke *gps_target = ED_gpencil_stroke_nearest_to_ends(
- p->C, &p->gsc, gpl, gpl->actframe, gps, GPENCIL_MINIMUM_JOIN_DIST, &pt_index);
+ bGPDstroke *gps_target = ED_gpencil_stroke_nearest_to_ends(p->C,
+ &p->gsc,
+ gpl,
+ gpl->actframe,
+ gps,
+ ctrl1,
+ ctrl2,
+ GPENCIL_MINIMUM_JOIN_DIST,
+ &pt_index);
if (gps_target != NULL) {
gps = ED_gpencil_stroke_join_and_trim(p->gpd, p->gpf, gps, gps_target, pt_index);
}
@@ -3568,7 +3581,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
// ToolSettings *ts = CTX_data_tool_settings(C);
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
- /* default exit state - pass through to support MMB view nav, etc. */
+ /* Default exit state - pass through to support MMB view navigation, etc. */
int estate = OPERATOR_PASS_THROUGH;
/* NOTE(mike erwin): Not quite what I was looking for, but a good start!
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 5ecb6d9a212..f8cfc130e35 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -1382,11 +1382,23 @@ static void gpencil_primitive_interaction_end(bContext *C,
if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) {
if (ELEM(tgpi->type, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_CURVE, GP_STROKE_POLYLINE)) {
if (gps->prev != NULL) {
+ BKE_gpencil_stroke_boundingbox_calc(gps);
+ float diff_mat[4][4], ctrl1[2], ctrl2[2];
+ BKE_gpencil_layer_transform_matrix_get(tgpi->depsgraph, tgpi->ob, tgpi->gpl, diff_mat);
+ ED_gpencil_stroke_extremes_to2d(&tgpi->gsc, diff_mat, gps, ctrl1, ctrl2);
+
int pt_index = 0;
bool doit = true;
while (doit && gps) {
- bGPDstroke *gps_target = ED_gpencil_stroke_nearest_to_ends(
- C, &tgpi->gsc, tgpi->gpl, gpf, gps, GPENCIL_MINIMUM_JOIN_DIST, &pt_index);
+ bGPDstroke *gps_target = ED_gpencil_stroke_nearest_to_ends(C,
+ &tgpi->gsc,
+ tgpi->gpl,
+ gpf,
+ gps,
+ ctrl1,
+ ctrl2,
+ GPENCIL_MINIMUM_JOIN_DIST,
+ &pt_index);
if (gps_target != NULL) {
gps = ED_gpencil_stroke_join_and_trim(tgpi->gpd, gpf, gps, gps_target, pt_index);
}
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 869254cef3b..e9a6beab798 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -337,7 +337,7 @@ static bool gpencil_brush_smooth_apply(tGP_BrushEditData *gso,
/* perform smoothing */
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
- BKE_gpencil_stroke_smooth(gps, pt_index, inf);
+ BKE_gpencil_stroke_smooth_point(gps, pt_index, inf);
}
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf);
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 93bae7d3614..6ad2fffc773 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -2347,7 +2347,7 @@ void GPENCIL_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_select_operation(ot);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 5cc52303cd6..bb05b93ad81 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -3213,11 +3213,28 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
return hit;
}
+/* Get extremes of stroke in 2D using current view. */
+void ED_gpencil_stroke_extremes_to2d(const GP_SpaceConversion *gsc,
+ const float diff_mat[4][4],
+ bGPDstroke *gps,
+ float r_ctrl1[2],
+ float r_ctrl2[2])
+{
+ bGPDspoint pt_dummy_ps;
+
+ gpencil_point_to_parent_space(&gps->points[0], diff_mat, &pt_dummy_ps);
+ gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &r_ctrl1[0], &r_ctrl1[1]);
+ gpencil_point_to_parent_space(&gps->points[gps->totpoints - 1], diff_mat, &pt_dummy_ps);
+ gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &r_ctrl2[0], &r_ctrl2[1]);
+}
+
bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
const GP_SpaceConversion *gsc,
bGPDlayer *gpl,
bGPDframe *gpf,
bGPDstroke *gps,
+ const float ctrl1[2],
+ const float ctrl2[2],
const float radius,
int *r_index)
{
@@ -3267,6 +3284,15 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_end[0], &pt2d_target_end[1]);
+ /* If the distance to the original stroke extremes is too big, the stroke must not be joined.
+ */
+ if ((len_squared_v2v2(ctrl1, pt2d_target_start) > radius_sqr) &&
+ (len_squared_v2v2(ctrl1, pt2d_target_end) > radius_sqr) &&
+ (len_squared_v2v2(ctrl2, pt2d_target_start) > radius_sqr) &&
+ (len_squared_v2v2(ctrl2, pt2d_target_end) > radius_sqr)) {
+ continue;
+ }
+
if ((len_squared_v2v2(pt2d_start, pt2d_target_start) > radius_sqr) &&
(len_squared_v2v2(pt2d_start, pt2d_target_end) > radius_sqr) &&
(len_squared_v2v2(pt2d_end, pt2d_target_start) > radius_sqr) &&
@@ -3350,7 +3376,7 @@ bGPDstroke *ED_gpencil_stroke_join_and_trim(
/* Join both strokes. */
int totpoint = gps_final->totpoints;
- BKE_gpencil_stroke_join(gps_final, gps, false, true);
+ BKE_gpencil_stroke_join(gps_final, gps, false, true, true);
/* Select the join points and merge if the distance is very small. */
pt = &gps_final->points[totpoint - 1];
diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c
index 402bccce2f7..5c3a7cf9e6f 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_ops.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c
@@ -588,6 +588,7 @@ static int gpencil_vertexpaint_set_exec(bContext *C, wmOperator *op)
changed = true;
copy_v3_v3(gps->vert_color_fill, brush->rgb);
gps->vert_color_fill[3] = factor;
+ srgb_to_linearrgb_v4(gps->vert_color_fill, gps->vert_color_fill);
}
/* Stroke points. */
@@ -596,10 +597,13 @@ static int gpencil_vertexpaint_set_exec(bContext *C, wmOperator *op)
int i;
bGPDspoint *pt;
+ float color[4];
+ copy_v3_v3(color, brush->rgb);
+ color[3] = factor;
+ srgb_to_linearrgb_v4(color, color);
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if ((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) {
- copy_v3_v3(pt->vert_color, brush->rgb);
- pt->vert_color[3] = factor;
+ copy_v3_v3(pt->vert_color, color);
}
}
}
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 75c02082bd3..6a0a42ee77b 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -678,6 +678,10 @@ void ANIM_draw_framerange(struct Scene *scene, struct View2D *v2d);
/* ------------- UI Panel Drawing -------------- */
+bool ANIM_nla_context_track_ptr(const struct bContext *C, struct PointerRNA *r_ptr);
+bool ANIM_nla_context_strip_ptr(const struct bContext *C, struct PointerRNA *r_ptr);
+
+struct NlaTrack *ANIM_nla_context_track(const struct bContext *C);
struct NlaStrip *ANIM_nla_context_strip(const struct bContext *C);
struct FCurve *ANIM_graph_context_fcurve(const struct bContext *C);
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 8a8d91a570c..c760b661373 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -391,8 +391,15 @@ struct bGPDstroke *ED_gpencil_stroke_nearest_to_ends(struct bContext *C,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
+ const float ctrl1[2],
+ const float ctrl2[2],
const float radius,
int *r_index);
+void ED_gpencil_stroke_extremes_to2d(const struct GP_SpaceConversion *gsc,
+ const float diff_mat[4][4],
+ struct bGPDstroke *gps,
+ float r_ctrl1[2],
+ float r_ctrl2[2]);
struct bGPDstroke *ED_gpencil_stroke_join_and_trim(struct bGPdata *gpd,
struct bGPDframe *gpf,
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index ec525806b81..6b0b9f4a27c 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -46,7 +46,6 @@ struct wmWindowManager;
struct Image *ED_space_image(struct SpaceImage *sima);
void ED_space_image_set(struct Main *bmain,
struct SpaceImage *sima,
- struct Object *obedit,
struct Image *ima,
bool automatic);
void ED_space_image_auto_set(const struct bContext *C, struct SpaceImage *sima);
diff --git a/source/blender/editors/include/ED_keyframes_keylist.h b/source/blender/editors/include/ED_keyframes_keylist.h
index 3a9750c1206..4194444ca0f 100644
--- a/source/blender/editors/include/ED_keyframes_keylist.h
+++ b/source/blender/editors/include/ED_keyframes_keylist.h
@@ -139,14 +139,20 @@ typedef enum eKeyframeExtremeDrawOpts {
struct AnimKeylist *ED_keylist_create(void);
void ED_keylist_free(struct AnimKeylist *keylist);
-const struct ActKeyColumn *ED_keylist_find_exact(const struct AnimKeylist *keylist, float cfra);
-const struct ActKeyColumn *ED_keylist_find_next(const struct AnimKeylist *keylist, float cfra);
-const struct ActKeyColumn *ED_keylist_find_prev(const struct AnimKeylist *keylist, float cfra);
+void ED_keylist_prepare_for_direct_access(struct AnimKeylist *keylist);
+const struct ActKeyColumn *ED_keylist_find_exact(const struct AnimKeylist *keylist,
+ const float cfra);
+const struct ActKeyColumn *ED_keylist_find_next(const struct AnimKeylist *keylist,
+ const float cfra);
+const struct ActKeyColumn *ED_keylist_find_prev(const struct AnimKeylist *keylist,
+ const float cfra);
const struct ActKeyColumn *ED_keylist_find_any_between(const struct AnimKeylist *keylist,
const Range2f frame_range);
bool ED_keylist_is_empty(const struct AnimKeylist *keylist);
const struct ListBase /* ActKeyColumn */ *ED_keylist_listbase(const struct AnimKeylist *keylist);
bool ED_keylist_frame_range(const struct AnimKeylist *keylist, Range2f *r_frame_range);
+const ActKeyColumn *ED_keylist_array(const struct AnimKeylist *keylist);
+int64_t ED_keylist_array_len(const struct AnimKeylist *keylist);
/* Key-data Generation --------------- */
@@ -197,8 +203,6 @@ void mask_to_keylist(struct bDopeSheet *ads,
struct AnimKeylist *keylist);
/* ActKeyColumn API ---------------- */
-/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
-short compare_ak_cfraPtr(void *node, void *data);
/* Checks if ActKeyColumn has any block data */
bool actkeyblock_is_valid(const ActKeyColumn *ac);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index a9cf04e1ad7..5397cd95ace 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -286,6 +286,7 @@ float ED_object_new_primitive_matrix(struct bContext *C,
struct Object *obedit,
const float loc[3],
const float rot[3],
+ const float scale[3],
float primmat[4][4]);
/* Avoid allowing too much insane values even by typing
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 69ac48d842f..bedd0e2fa35 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -109,7 +109,8 @@ bool BIF_createTransformOrientation(struct bContext *C,
const bool overwrite);
void BIF_selectTransformOrientation(struct bContext *C, struct TransformOrientation *target);
-void ED_getTransformOrientationMatrix(const struct bContext *C,
+void ED_getTransformOrientationMatrix(struct ViewLayer *view_layer,
+ const struct View3D *v3d,
struct Object *ob,
struct Object *obedit,
const short around,
@@ -145,15 +146,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags);
/* *** transform_orientations.c *** */
void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat[3][3]);
-short ED_transform_calc_orientation_from_type_ex(const struct bContext *C,
- float r_mat[3][3],
- /* extra args */
- struct Scene *scene,
- struct RegionView3D *rv3d,
+short ED_transform_calc_orientation_from_type_ex(const struct Scene *scene,
+ struct ViewLayer *view_layer,
+ const struct View3D *v3d,
+ const struct RegionView3D *rv3d,
struct Object *ob,
struct Object *obedit,
const short orientation_index,
- const int pivot_point);
+ const int pivot_point,
+ float r_mat[3][3]);
/* transform gizmos */
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 2c958d282f9..cf8dcbd7995 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -566,6 +566,13 @@ eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const struct Scene *sce
void view3d_opengl_select_cache_begin(void);
void view3d_opengl_select_cache_end(void);
+int view3d_opengl_select_ex(struct ViewContext *vc,
+ unsigned int *buffer,
+ unsigned int bufsize,
+ const struct rcti *input,
+ eV3DSelectMode select_mode,
+ eV3DSelectObjectFilter select_filter,
+ const bool do_material_slot_selection);
int view3d_opengl_select(struct ViewContext *vc,
unsigned int *buffer,
unsigned int bufsize,
@@ -638,6 +645,9 @@ void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
struct Object *ED_view3d_give_object_under_cursor(struct bContext *C, const int mval[2]);
+struct Object *ED_view3d_give_material_slot_under_cursor(struct bContext *C,
+ const int mval[2],
+ int *r_material_slot);
bool ED_view3d_is_object_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *area, struct ARegion *region, bool do_clip);
void ED_view3d_update_viewmat(struct Depsgraph *depsgraph,
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 1708c3598b1..ddd9ca4a98c 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -490,9 +490,9 @@ DEF_ICON_MODIFIER(CON_ACTION)
DEF_ICON_BLANK(745)
DEF_ICON_BLANK(746)
DEF_ICON_BLANK(747)
-DEF_ICON_BLANK(748)
-DEF_ICON_BLANK(749)
-DEF_ICON_BLANK(750)
+DEF_ICON_MODIFIER(MOD_LENGTH)
+DEF_ICON_MODIFIER(MOD_DASH)
+DEF_ICON_MODIFIER(MOD_LINEART)
DEF_ICON_BLANK(751)
DEF_ICON(HOLDOUT_OFF)
DEF_ICON(HOLDOUT_ON)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 7211cf9f893..916105b0f8e 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2209,6 +2209,11 @@ enum uiTemplateListFlags {
UI_TEMPLATE_LIST_SORT_LOCK = (1 << 1),
/* Don't allow resizing the list, i.e. don't add the grip button. */
UI_TEMPLATE_LIST_NO_GRIP = (1 << 2),
+ /** Do not show filtering options, not even the button to expand/collapse them. Also hides the
+ * grip button. */
+ UI_TEMPLATE_LIST_NO_FILTER_OPTIONS = (1 << 3),
+ /** For #UILST_LAYOUT_BIG_PREVIEW_GRID, don't reserve space for the name label. */
+ UI_TEMPLATE_LIST_NO_NAMES = (1 << 4),
UI_TEMPLATE_LIST_FLAGS_LAST
};
@@ -2289,6 +2294,12 @@ int uiTemplateRecentFiles(struct uiLayout *layout, int rows);
void uiTemplateFileSelectPath(uiLayout *layout,
struct bContext *C,
struct FileSelectParams *params);
+
+enum {
+ UI_TEMPLATE_ASSET_DRAW_NO_NAMES = (1 << 0),
+ UI_TEMPLATE_ASSET_DRAW_NO_FILTER = (1 << 1),
+ UI_TEMPLATE_ASSET_DRAW_NO_LIBRARY = (1 << 2),
+};
void uiTemplateAssetView(struct uiLayout *layout,
struct bContext *C,
const char *list_id,
@@ -2299,6 +2310,7 @@ void uiTemplateAssetView(struct uiLayout *layout,
struct PointerRNA *active_dataptr,
const char *active_propname,
const struct AssetFilterSettings *filter_settings,
+ const int display_flags,
const char *activate_opname,
struct PointerRNA *r_activate_op_properties,
const char *drag_opname,
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index b953d88c896..bb9e813ea50 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -70,26 +70,12 @@ static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but)
/* If this returns null, we won't be able to bind shortcuts to these RNA properties.
* Support can be added at #wm_context_member_from_ptr. */
- const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin);
- if (member_id == NULL) {
+ char *final_data_path = WM_context_path_resolve_property_full(
+ C, &but->rnapoin, but->rnaprop, but->rnaindex);
+ if (final_data_path == NULL) {
return NULL;
}
- const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin);
- const char *member_id_data_path = member_id;
-
- if (data_path) {
- member_id_data_path = BLI_sprintfN("%s.%s", member_id, data_path);
- MEM_freeN((void *)data_path);
- }
-
- const char *prop_id = RNA_property_identifier(but->rnaprop);
- const char *final_data_path = BLI_sprintfN("%s.%s", member_id_data_path, prop_id);
-
- if (member_id != member_id_data_path) {
- MEM_freeN((void *)member_id_data_path);
- }
-
/* Create ID property of data path, to pass to the operator. */
const IDPropertyTemplate val = {0};
IDProperty *prop = IDP_New(IDP_GROUP, &val, __func__);
@@ -329,10 +315,24 @@ static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
static bool ui_but_is_user_menu_compatible(bContext *C, uiBut *but)
{
- return (but->optype ||
- (but->rnaprop && (RNA_property_type(but->rnaprop) == PROP_BOOLEAN) &&
- (WM_context_member_from_ptr(C, &but->rnapoin) != NULL)) ||
- UI_but_menutype_get(but));
+ bool result = false;
+ if (but->optype) {
+ result = true;
+ }
+ else if (but->rnaprop) {
+ if (RNA_property_type(but->rnaprop) == PROP_BOOLEAN) {
+ char *data_path = WM_context_path_resolve_full(C, &but->rnapoin);
+ if (data_path != NULL) {
+ MEM_freeN(data_path);
+ result = true;
+ }
+ }
+ }
+ else if (UI_but_menutype_get(but)) {
+ result = true;
+ }
+
+ return result;
}
static bUserMenuItem *ui_but_user_menu_find(bContext *C, uiBut *but, bUserMenu *um)
@@ -343,21 +343,11 @@ static bUserMenuItem *ui_but_user_menu_find(bContext *C, uiBut *but, bUserMenu *
&um->items, but->optype, prop, but->opcontext);
}
if (but->rnaprop) {
- const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin);
- const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin);
- const char *member_id_data_path = member_id;
- if (data_path) {
- member_id_data_path = BLI_sprintfN("%s.%s", member_id, data_path);
- }
+ char *member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin);
const char *prop_id = RNA_property_identifier(but->rnaprop);
bUserMenuItem *umi = (bUserMenuItem *)ED_screen_user_menu_item_find_prop(
&um->items, member_id_data_path, prop_id, but->rnaindex);
- if (data_path) {
- MEM_freeN((void *)data_path);
- }
- if (member_id != member_id_data_path) {
- MEM_freeN((void *)member_id_data_path);
- }
+ MEM_freeN(member_id_data_path);
return umi;
}
@@ -412,21 +402,11 @@ static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um)
}
else if (but->rnaprop) {
/* NOTE: 'member_id' may be a path. */
- const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin);
- const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin);
- const char *member_id_data_path = member_id;
- if (data_path) {
- member_id_data_path = BLI_sprintfN("%s.%s", member_id, data_path);
- }
+ char *member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin);
const char *prop_id = RNA_property_identifier(but->rnaprop);
/* NOTE: ignore 'drawstr', use property idname always. */
ED_screen_user_menu_item_add_prop(&um->items, "", member_id_data_path, prop_id, but->rnaindex);
- if (data_path) {
- MEM_freeN((void *)data_path);
- }
- if (member_id != member_id_data_path) {
- MEM_freeN((void *)member_id_data_path);
- }
+ MEM_freeN(member_id_data_path);
}
else if ((mt = UI_but_menutype_get(but))) {
ED_screen_user_menu_item_add_menu(&um->items, drawstr, mt);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 977e9661dd9..77ae16d7cc7 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -508,6 +508,7 @@ typedef struct uiAfterFunc {
bContextStore *context;
char undostr[BKE_UNDO_STR_MAX];
+ char drawstr[UI_MAX_DRAW_STR];
} uiAfterFunc;
static void button_activate_init(bContext *C,
@@ -790,6 +791,10 @@ static void ui_handle_afterfunc_add_operator_ex(wmOperatorType *ot,
if (context_but && context_but->context) {
after->context = CTX_store_copy(context_but->context);
}
+
+ if (context_but) {
+ ui_but_drawstr_without_sep_char(context_but, after->drawstr, sizeof(after->drawstr));
+ }
}
void ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext)
@@ -900,6 +905,8 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
after->context = CTX_store_copy(but->context);
}
+ ui_but_drawstr_without_sep_char(but, after->drawstr, sizeof(after->drawstr));
+
but->optype = NULL;
but->opcontext = 0;
but->opptr = NULL;
@@ -1021,7 +1028,8 @@ static void ui_apply_but_funcs_after(bContext *C)
}
if (after.optype) {
- WM_operator_name_call_ptr(C, after.optype, after.opcontext, (after.opptr) ? &opptr : NULL);
+ WM_operator_name_call_ptr_with_depends_on_cursor(
+ C, after.optype, after.opcontext, (after.opptr) ? &opptr : NULL, after.drawstr);
}
if (after.opptr) {
@@ -4190,10 +4198,11 @@ static void ui_but_extra_operator_icon_apply(bContext *C, uiBut *but, uiButExtra
ui_apply_but(C, but->block, but, but->active, true);
}
button_activate_state(C, but, BUTTON_STATE_EXIT);
- WM_operator_name_call_ptr(C,
- op_icon->optype_params->optype,
- op_icon->optype_params->opcontext,
- op_icon->optype_params->opptr);
+ WM_operator_name_call_ptr_with_depends_on_cursor(C,
+ op_icon->optype_params->optype,
+ op_icon->optype_params->opcontext,
+ op_icon->optype_params->opptr,
+ NULL);
/* Force recreation of extra operator icons (pseudo update). */
ui_but_extra_operator_icons_free(but);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index ec5a30f7793..66c75c63050 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -921,10 +921,10 @@ static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_
{
uiBut *but = but_v;
- RNA_boolean_set(&but->rnapoin, "shift", (but->modifier_key & KM_SHIFT) != 0);
- RNA_boolean_set(&but->rnapoin, "ctrl", (but->modifier_key & KM_CTRL) != 0);
- RNA_boolean_set(&but->rnapoin, "alt", (but->modifier_key & KM_ALT) != 0);
- RNA_boolean_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) != 0);
+ RNA_int_set(&but->rnapoin, "shift", (but->modifier_key & KM_SHIFT) ? KM_MOD_HELD : KM_NOTHING);
+ RNA_int_set(&but->rnapoin, "ctrl", (but->modifier_key & KM_CTRL) ? KM_MOD_HELD : KM_NOTHING);
+ RNA_int_set(&but->rnapoin, "alt", (but->modifier_key & KM_ALT) ? KM_MOD_HELD : KM_NOTHING);
+ RNA_int_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) ? KM_MOD_HELD : KM_NOTHING);
}
/**
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index 9b601727e29..f27b37a27de 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -46,6 +46,7 @@
struct AssetViewListData {
AssetLibraryReference asset_library_ref;
bScreen *screen;
+ bool show_names;
};
static void asset_view_item_but_drag_set(uiBut *but,
@@ -95,14 +96,15 @@ static void asset_view_draw_item(uiList *ui_list,
uiLayoutSetContextPointer(layout, "asset_handle", itemptr);
uiBlock *block = uiLayoutGetBlock(layout);
+ const bool show_names = list_data->show_names;
/* TODO ED_fileselect_init_layout(). Share somehow? */
const float size_x = (96.0f / 20.0f) * UI_UNIT_X;
- const float size_y = (96.0f / 20.0f) * UI_UNIT_Y;
+ const float size_y = (96.0f / 20.0f) * UI_UNIT_Y - (show_names ? 0 : UI_UNIT_Y);
uiBut *but = uiDefIconTextBut(block,
UI_BTYPE_PREVIEW_TILE,
0,
ED_asset_handle_get_preview_icon_id(asset_handle),
- ED_asset_handle_get_name(asset_handle),
+ show_names ? ED_asset_handle_get_name(asset_handle) : "",
0,
0,
size_x,
@@ -202,6 +204,7 @@ void uiTemplateAssetView(uiLayout *layout,
PointerRNA *active_dataptr,
const char *active_propname,
const AssetFilterSettings *filter_settings,
+ const int display_flags,
const char *activate_opname,
PointerRNA *r_activate_op_properties,
const char *drag_opname,
@@ -220,9 +223,11 @@ void uiTemplateAssetView(uiLayout *layout,
RNA_property_enum_get(asset_library_dataptr, asset_library_prop));
uiLayout *row = uiLayoutRow(col, true);
- uiItemFullR(row, asset_library_dataptr, asset_library_prop, RNA_NO_INDEX, 0, 0, "", 0);
- if (asset_library_ref.type != ASSET_LIBRARY_LOCAL) {
- uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_list_refresh");
+ if ((display_flags & UI_TEMPLATE_ASSET_DRAW_NO_LIBRARY) == 0) {
+ uiItemFullR(row, asset_library_dataptr, asset_library_prop, RNA_NO_INDEX, 0, 0, "", 0);
+ if (asset_library_ref.type != ASSET_LIBRARY_LOCAL) {
+ uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_list_refresh");
+ }
}
ED_assetlist_storage_fetch(&asset_library_ref, C);
@@ -236,6 +241,15 @@ void uiTemplateAssetView(uiLayout *layout,
"AssetViewListData");
list_data->asset_library_ref = asset_library_ref;
list_data->screen = CTX_wm_screen(C);
+ list_data->show_names = (display_flags & UI_TEMPLATE_ASSET_DRAW_NO_NAMES) == 0;
+
+ uiTemplateListFlags template_list_flags = UI_TEMPLATE_LIST_NO_GRIP;
+ if ((display_flags & UI_TEMPLATE_ASSET_DRAW_NO_NAMES) != 0) {
+ template_list_flags |= UI_TEMPLATE_LIST_NO_NAMES;
+ }
+ if ((display_flags & UI_TEMPLATE_ASSET_DRAW_NO_FILTER) != 0) {
+ template_list_flags |= UI_TEMPLATE_LIST_NO_FILTER_OPTIONS;
+ }
/* TODO can we have some kind of model-view API to handle referencing, filtering and lazy loading
* (of previews) of the items? */
@@ -252,7 +266,7 @@ void uiTemplateAssetView(uiLayout *layout,
0,
UILST_LAYOUT_BIG_PREVIEW_GRID,
0,
- UI_TEMPLATE_LIST_NO_GRIP,
+ template_list_flags,
list_data);
if (!list) {
/* List creation failed. */
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index 0ab45ea0f81..8246759ad36 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -944,10 +944,16 @@ static void ui_template_list_layout_draw(bContext *C,
/* For scrollbar. */
row = uiLayoutRow(glob, false);
+ const bool show_names = (flags & UI_TEMPLATE_LIST_NO_NAMES) == 0;
+
/* TODO ED_fileselect_init_layout(). Share somehow? */
float size_x = (96.0f / 20.0f) * UI_UNIT_X;
float size_y = (96.0f / 20.0f) * UI_UNIT_Y;
+ if (!show_names) {
+ size_y -= UI_UNIT_Y;
+ }
+
const int cols_per_row = MAX2((uiLayoutGetWidth(box) - V2D_SCROLL_WIDTH) / size_x, 1);
uiLayout *grid = uiLayoutGridFlow(row, true, cols_per_row, true, true, true);
@@ -1033,7 +1039,8 @@ static void ui_template_list_layout_draw(bContext *C,
break;
}
- if (glob) {
+ const bool add_filters_but = (flags & UI_TEMPLATE_LIST_NO_FILTER_OPTIONS) == 0;
+ if (glob && add_filters_but) {
const bool add_grip_but = (flags & UI_TEMPLATE_LIST_NO_GRIP) == 0;
/* About #UI_BTYPE_GRIP drag-resize:
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c
index 3105891142f..672f1b64943 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.c
@@ -955,7 +955,8 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
switch (item->type) {
case MENU_SEARCH_TYPE_OP: {
CTX_store_set(C, item->op.context);
- WM_operator_name_call_ptr(C, item->op.type, item->op.opcontext, item->op.opptr);
+ WM_operator_name_call_ptr_with_depends_on_cursor(
+ C, item->op.type, item->op.opcontext, item->op.opptr, item->drawstr);
CTX_store_set(C, NULL);
break;
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 08d78552710..0c9eb20af19 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -673,8 +673,8 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
}
}
else {
- if (BKE_lib_id_make_local(bmain, id, false, 0)) {
- BKE_main_id_newptr_and_tag_clear(bmain);
+ if (BKE_lib_id_make_local(bmain, id, 0)) {
+ BKE_id_newptr_and_tag_clear(id);
/* Reassign to get proper updates/notifiers. */
idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
@@ -1031,7 +1031,7 @@ static void template_ID(const bContext *C,
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else {
- const bool disabled = (!BKE_lib_id_make_local(CTX_data_main(C), id, true /* test */, 0) ||
+ const bool disabled = (!BKE_idtype_idcode_is_localizable(GS(id->name)) ||
(idfrom && idfrom->lib));
but = uiDefIconBut(block,
UI_BTYPE_BUT,
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index a2b86ccd947..0dc7c2d3f9a 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -5443,13 +5443,20 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
rcti trect = *rect;
const float text_size = UI_UNIT_Y;
float font_dims[2] = {0.0f, 0.0f};
+ const bool has_text = name && name[0];
- /* draw icon in rect above the space reserved for the label */
- rect->ymin += text_size;
+ if (has_text) {
+ /* draw icon in rect above the space reserved for the label */
+ rect->ymin += text_size;
+ }
GPU_blend(GPU_BLEND_ALPHA);
widget_draw_preview(iconid, 1.0f, rect);
GPU_blend(GPU_BLEND_NONE);
+ if (!has_text) {
+ return;
+ }
+
BLF_width_and_height(
fstyle->uifont_id, name, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 6a1be8dcef3..fe6acac7d29 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -629,7 +629,7 @@ void MASK_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index a64b90e15a3..c826da74010 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -73,11 +73,7 @@ static Object *make_prim_init(bContext *C,
r_creation_data->was_editmode = true;
}
- ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat);
-
- if (scale) {
- rescale_m4(r_creation_data->mat, scale);
- }
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, scale, r_creation_data->mat);
return obedit;
}
@@ -351,7 +347,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
op,
"verts.out",
false,
- "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b "
+ "create_cone segments=%i radius1=%f radius2=%f cap_ends=%b "
"cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"),
RNA_float_get(op->ptr, "radius"),
@@ -427,7 +423,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
op,
"verts.out",
false,
- "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b "
+ "create_cone segments=%i radius1=%f radius2=%f cap_ends=%b "
"cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"),
RNA_float_get(op->ptr, "radius1"),
@@ -642,7 +638,7 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
op,
"verts.out",
false,
- "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b",
+ "create_uvsphere u_segments=%i v_segments=%i radius=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "segments"),
RNA_int_get(op->ptr, "ring_count"),
RNA_float_get(op->ptr, "radius"),
@@ -710,7 +706,7 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
op,
"verts.out",
false,
- "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b",
+ "create_icosphere subdivisions=%i radius=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "subdivisions"),
RNA_float_get(op->ptr, "radius"),
creation_data.mat,
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 01736f2919a..0d74187b50e 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -97,7 +97,6 @@ typedef struct {
int launch_event;
float mcenter[2];
void *draw_handle_pixel;
- short gizmo_flag;
short value_mode; /* Which value does mouse movement and numeric input affect? */
float segments; /* Segments as float so smooth mouse pan works in small increments */
@@ -307,11 +306,6 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->draw_handle_pixel = ED_region_draw_cb_activate(
region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
-
- if (v3d) {
- opdata->gizmo_flag = v3d->gizmo_flag;
- v3d->gizmo_flag = V3D_GIZMO_HIDE;
- }
}
return true;
@@ -433,15 +427,11 @@ static void edbm_bevel_exit(bContext *C, wmOperator *op)
}
if (opdata->is_modal) {
- View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup);
}
ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel);
- if (v3d) {
- v3d->gizmo_flag = opdata->gizmo_flag;
- }
G.moving = 0;
}
MEM_SAFE_FREE(opdata->ob_store);
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 3c8afe8e7db..27a1bf9658f 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -72,7 +72,6 @@ typedef struct {
bool is_dirty;
} * backup;
int backup_len;
- short gizmo_flag;
} BisectData;
static void mesh_bisect_interactive_calc(bContext *C,
@@ -88,6 +87,7 @@ static void mesh_bisect_interactive_calc(bContext *C,
int y_start = RNA_int_get(op->ptr, "ystart");
int x_end = RNA_int_get(op->ptr, "xend");
int y_end = RNA_int_get(op->ptr, "yend");
+ const bool use_flip = RNA_boolean_get(op->ptr, "flip");
/* reference location (some point in front of the view) for finding a point on a plane */
const float *co_ref = rv3d->ofs;
@@ -105,6 +105,9 @@ static void mesh_bisect_interactive_calc(bContext *C,
/* cross both to get a normal */
cross_v3_v3v3(plane_no, co_a, co_b);
normalize_v3(plane_no); /* not needed but nicer for user */
+ if (use_flip) {
+ negate_v3(plane_no);
+ }
/* point on plane, can use either start or endpoint */
ED_view3d_win_to_3d(v3d, region, co_ref, co_a_ss, plane_co);
@@ -116,7 +119,7 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int valid_objects = 0;
/* If the properties are set or there is no rv3d,
- * skip model and exec immediately. */
+ * skip modal and exec immediately. */
if ((CTX_wm_region_view3d(C) == NULL) || (RNA_struct_property_is_set(op->ptr, "plane_co") &&
RNA_struct_property_is_set(op->ptr, "plane_no"))) {
return mesh_bisect_exec(C, op);
@@ -140,10 +143,19 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- int ret = WM_gesture_straightline_invoke(C, op, event);
- if (ret & OPERATOR_RUNNING_MODAL) {
- View3D *v3d = CTX_wm_view3d(C);
+ /* Support flipping if side matters. */
+ int ret;
+ const bool clear_inner = RNA_boolean_get(op->ptr, "clear_inner");
+ const bool clear_outer = RNA_boolean_get(op->ptr, "clear_outer");
+ const bool use_fill = RNA_boolean_get(op->ptr, "use_fill");
+ if ((clear_inner != clear_outer) || use_fill) {
+ ret = WM_gesture_straightline_active_side_invoke(C, op, event);
+ }
+ else {
+ ret = WM_gesture_straightline_invoke(C, op, event);
+ }
+ if (ret & OPERATOR_RUNNING_MODAL) {
wmGesture *gesture = op->customdata;
BisectData *opdata;
@@ -166,8 +178,6 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* Misc other vars. */
G.moving = G_TRANSFORM_EDIT;
- opdata->gizmo_flag = v3d->gizmo_flag;
- v3d->gizmo_flag = V3D_GIZMO_HIDE;
/* Initialize modal callout. */
ED_workspace_status_text(C, TIP_("LMB: Click and drag to draw cut line"));
@@ -176,10 +186,8 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return ret;
}
-static void edbm_bisect_exit(bContext *C, BisectData *opdata)
+static void edbm_bisect_exit(BisectData *opdata)
{
- View3D *v3d = CTX_wm_view3d(C);
- v3d->gizmo_flag = opdata->gizmo_flag;
G.moving = 0;
for (int ob_index = 0; ob_index < opdata->backup_len; ob_index++) {
@@ -210,7 +218,7 @@ static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (ret & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
- edbm_bisect_exit(C, &opdata_back);
+ edbm_bisect_exit(&opdata_back);
#ifdef USE_GIZMO
/* Setup gizmos */
@@ -769,7 +777,7 @@ static void MESH_GGT_bisect(struct wmGizmoGroupType *gzgt)
gzgt->name = "Mesh Bisect";
gzgt->idname = "MESH_GGT_bisect";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D;
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 907881a44f3..e4cd48d95bb 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -925,7 +925,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Duplicate or Extrude to Cursor";
+ ot->name = "Extrude to Cursor or Add";
ot->idname = "MESH_OT_dupli_extrude_cursor";
ot->description =
"Duplicate and extrude selected vertices, edges or faces towards the mouse cursor";
@@ -935,7 +935,7 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
ot->poll = ED_operator_editmesh_region_view3d;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
RNA_def_boolean(ot->srna,
"rotate_source",
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index 18f51ae9df2..7be169f70f4 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -76,7 +76,6 @@ typedef struct {
int launch_event;
float mcenter[2];
void *draw_handle_pixel;
- short gizmo_flag;
} InsetData;
static void edbm_inset_update_header(wmOperator *op, bContext *C)
@@ -177,7 +176,6 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->num_input.unit_type[1] = B_UNIT_LENGTH;
if (is_modal) {
- View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
@@ -189,10 +187,6 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->draw_handle_pixel = ED_region_draw_cb_activate(
region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
- if (v3d) {
- opdata->gizmo_flag = v3d->gizmo_flag;
- v3d->gizmo_flag = V3D_GIZMO_HIDE;
- }
}
return true;
@@ -206,15 +200,11 @@ static void edbm_inset_exit(bContext *C, wmOperator *op)
opdata = op->customdata;
if (opdata->is_modal) {
- View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup);
}
ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel);
- if (v3d) {
- v3d->gizmo_flag = opdata->gizmo_flag;
- }
G.moving = 0;
}
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 5a2a090b725..d1df063d9d0 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -1085,7 +1085,7 @@ static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
EDBM_update(obedit->data,
&(const struct EDBMUpdate_Params){
.calc_looptri = true,
- .calc_normals = false,
+ .calc_normals = true,
.is_destructive = true,
});
}
@@ -1124,7 +1124,7 @@ void MESH_OT_rip(wmOperatorType *ot)
ot->poll = EDBM_view3d_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* to give to transform */
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c
index f7e88284d93..ce49f0f80a3 100644
--- a/source/blender/editors/mesh/editmesh_rip_edge.c
+++ b/source/blender/editors/mesh/editmesh_rip_edge.c
@@ -249,7 +249,7 @@ void MESH_OT_rip_edge(wmOperatorType *ot)
ot->poll = EDBM_view3d_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* to give to transform */
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 8e38d41f971..2fcf8fa6f8f 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -4871,8 +4871,15 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op)
float axis_mat[3][3];
/* 3D view variables may be NULL, (no need to check in poll function). */
- ED_transform_calc_orientation_from_type_ex(
- C, axis_mat, scene, CTX_wm_region_view3d(C), obedit, obedit, orientation, V3D_AROUND_ACTIVE);
+ ED_transform_calc_orientation_from_type_ex(scene,
+ view_layer,
+ CTX_wm_view3d(C),
+ CTX_wm_region_view3d(C),
+ obedit,
+ obedit,
+ orientation,
+ V3D_AROUND_ACTIVE,
+ axis_mat);
const float *axis_vector = axis_mat[axis];
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 956658bd2b7..122214b87d5 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -4323,7 +4323,7 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
ot->poll = EDBM_view3d_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
PropertyRNA *prop;
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 27fb21e1dfb..1b720f2c14d 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -424,6 +424,11 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
/* remove tessface to ensure we don't hold references to invalid faces */
BKE_mesh_tessface_clear(me);
+ /* Clear any run-time data.
+ * Even though this mesh wont typically have run-time data, the Python API can for e.g.
+ * create loop-triangle cache here, which is confusing when left in the mesh, see: T90798. */
+ BKE_mesh_runtime_clear_geometry(me);
+
/* new material indices and material array */
if (totmat) {
matar = MEM_callocN(sizeof(*matar) * totmat, "join_mesh matar");
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 18f2b58eb65..040b5cd5066 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -37,6 +37,9 @@ set(INC
../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
+
+ # dna_type_offsets.h in BLO_read_write.h
+ ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern
)
set(SRC
@@ -93,3 +96,5 @@ if(WITH_EXPERIMENTAL_FEATURES)
endif()
blender_add_lib(bf_editor_object "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+add_dependencies(bf_editor_object bf_dna)
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 2e34284f46e..beadbf2689e 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -332,8 +332,12 @@ void ED_object_base_init_transform_on_add(Object *object, const float loc[3], co
/* Uses context to figure out transform for primitive.
* Returns standard diameter. */
-float ED_object_new_primitive_matrix(
- bContext *C, Object *obedit, const float loc[3], const float rot[3], float r_primmat[4][4])
+float ED_object_new_primitive_matrix(bContext *C,
+ Object *obedit,
+ const float loc[3],
+ const float rot[3],
+ const float scale[3],
+ float r_primmat[4][4])
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -356,6 +360,10 @@ float ED_object_new_primitive_matrix(
invert_m3_m3(imat, mat);
mul_m3_v3(imat, r_primmat[3]);
+ if (scale != NULL) {
+ rescale_m4(r_primmat, scale);
+ }
+
{
const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) :
ED_scene_grid_scale(scene, NULL);
@@ -863,7 +871,7 @@ static int effector_add_exec(bContext *C, wmOperator *op)
ED_object_editmode_enter_ex(bmain, scene, ob, 0);
float mat[4][4];
- ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, NULL, mat);
mul_mat3_m4_fl(mat, dia);
BLI_addtail(&cu->editnurb->nurbs,
ED_curve_add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, 1));
@@ -999,7 +1007,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
}
float mat[4][4];
- ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, NULL, mat);
/* Halving here is done to account for constant values from #BKE_mball_element_add.
* While the default radius of the resulting meta element is 2,
* we want to pass in 1 so other values such as resolution are scaled by 1.0. */
@@ -1365,30 +1373,28 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
case GP_EMPTY: {
float mat[4][4];
- ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, NULL, mat);
ED_gpencil_create_blank(C, ob, mat);
break;
}
case GP_STROKE: {
float radius = RNA_float_get(op->ptr, "radius");
+ float scale[3];
+ copy_v3_fl(scale, radius);
float mat[4][4];
- ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
- mul_v3_fl(mat[0], radius);
- mul_v3_fl(mat[1], radius);
- mul_v3_fl(mat[2], radius);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, scale, mat);
ED_gpencil_create_stroke(C, ob, mat);
break;
}
case GP_MONKEY: {
float radius = RNA_float_get(op->ptr, "radius");
+ float scale[3];
+ copy_v3_fl(scale, radius);
float mat[4][4];
- ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
- mul_v3_fl(mat[0], radius);
- mul_v3_fl(mat[1], radius);
- mul_v3_fl(mat[2], radius);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, scale, mat);
ED_gpencil_create_monkey(C, ob, mat);
break;
@@ -1397,12 +1403,11 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
case GP_LRT_COLLECTION:
case GP_LRT_OBJECT: {
float radius = RNA_float_get(op->ptr, "radius");
+ float scale[3];
+ copy_v3_fl(scale, radius);
float mat[4][4];
- ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
- mul_v3_fl(mat[0], radius);
- mul_v3_fl(mat[1], radius);
- mul_v3_fl(mat[2], radius);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, scale, mat);
ED_gpencil_create_lineart(C, ob);
@@ -2246,13 +2251,6 @@ static bool dupliobject_instancer_cmp(const void *a_, const void *b_)
return false;
}
-static bool object_has_geometry_set_instances(const Object *object_eval)
-{
- struct GeometrySet *geometry_set = object_eval->runtime.geometry_set_eval;
-
- return (geometry_set != NULL) && BKE_geometry_set_has_instances(geometry_set);
-}
-
static void make_object_duplilist_real(bContext *C,
Depsgraph *depsgraph,
Scene *scene,
@@ -2266,7 +2264,8 @@ static void make_object_duplilist_real(bContext *C,
Object *object_eval = DEG_get_evaluated_object(depsgraph, base->object);
- if (!(base->object->transflag & OB_DUPLI) && !object_has_geometry_set_instances(object_eval)) {
+ if (!(base->object->transflag & OB_DUPLI) &&
+ !BKE_object_has_geometry_set_instances(object_eval)) {
return;
}
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index e0419e0a4cc..8702b18a46f 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -1786,7 +1786,8 @@ static bool constraint_copy_to_selected_poll(bContext *C)
if (pchan) {
bool found = false;
- CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, chan, selected_pose_bones, Object *, UNUSED(ob)) {
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, chan, selected_pose_bones, Object *, ob) {
+ UNUSED_VARS(ob);
if (pchan != chan) {
/** NOTE: Can not return here, because CTX_DATA_BEGIN_WITH_ID allocated
* a list that needs to be freed by CTX_DATA_END. */
@@ -1862,6 +1863,7 @@ static int constraint_move_down_exec(bContext *C, wmOperator *op)
BLI_remlink(conlist, con);
BLI_insertlinkafter(conlist, nextCon, con);
+ ED_object_constraint_update(CTX_data_main(C), ob);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
return OPERATOR_FINISHED;
@@ -1917,6 +1919,7 @@ static int constraint_move_up_exec(bContext *C, wmOperator *op)
BLI_remlink(conlist, con);
BLI_insertlinkbefore(conlist, prevCon, con);
+ ED_object_constraint_update(CTX_data_main(C), ob);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
return OPERATOR_FINISHED;
@@ -1970,6 +1973,8 @@ static int constraint_move_to_index_exec(bContext *C, wmOperator *op)
if (con) {
ED_object_constraint_move_to_index(ob, con, new_index);
+ ED_object_constraint_update(CTX_data_main(C), ob);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index 3995728c428..e3c2932e17a 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
@@ -35,6 +36,7 @@
#include "BLI_listbase.h"
#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
@@ -55,6 +57,8 @@
#include "ED_object.h"
#include "ED_screen.h"
+#include "BLT_translation.h"
+
#include "UI_interface.h"
#include "WM_api.h"
@@ -939,3 +943,237 @@ void OBJECT_OT_gpencil_modifier_copy_to_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
gpencil_edit_modifier_properties(ot);
}
+
+/************************* Dash Modifier *******************************/
+
+static bool dash_segment_poll(bContext *C)
+{
+ return gpencil_edit_modifier_poll_generic(C, &RNA_DashGpencilModifierData, 0, false);
+}
+
+static bool dash_segment_name_exists_fn(void *arg, const char *name)
+{
+ const DashGpencilModifierData *dmd = (const DashGpencilModifierData *)arg;
+ for (int i = 0; i < dmd->segments_len; i++) {
+ if (STREQ(dmd->segments[i].name, name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static int dash_segment_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
+ op, ob, eGpencilModifierType_Dash);
+
+ const int new_active_index = dmd->segment_active_index + 1;
+ DashGpencilModifierSegment *new_segments = MEM_malloc_arrayN(
+ dmd->segments_len + 1, sizeof(DashGpencilModifierSegment), __func__);
+
+ if (dmd->segments_len != 0) {
+ /* Copy the segments before the new segment. */
+ memcpy(new_segments, dmd->segments, sizeof(DashGpencilModifierSegment) * new_active_index);
+ /* Copy the segments after the new segment. */
+ memcpy(new_segments + new_active_index + 1,
+ dmd->segments + new_active_index,
+ sizeof(DashGpencilModifierSegment) * (dmd->segments_len - new_active_index));
+ }
+
+ /* Create the new segment. */
+ DashGpencilModifierSegment *ds = &new_segments[new_active_index];
+ memcpy(
+ ds, DNA_struct_default_get(DashGpencilModifierSegment), sizeof(DashGpencilModifierSegment));
+ BLI_uniquename_cb(
+ dash_segment_name_exists_fn, dmd, DATA_("Segment"), '.', ds->name, sizeof(ds->name));
+ ds->dmd = dmd;
+
+ MEM_SAFE_FREE(dmd->segments);
+ dmd->segments = new_segments;
+ dmd->segments_len++;
+ dmd->segment_active_index++;
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int dash_segment_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op, NULL, NULL)) {
+ return dash_segment_add_exec(C, op);
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void GPENCIL_OT_segment_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Segment";
+ ot->description = "Add a segment to the dash modifier";
+ ot->idname = "GPENCIL_OT_segment_add";
+
+ /* api callbacks */
+ ot->poll = dash_segment_poll;
+ ot->invoke = dash_segment_add_invoke;
+ ot->exec = dash_segment_add_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
+
+static int dash_segment_remove_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+
+ DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
+ op, ob, eGpencilModifierType_Dash);
+
+ if (dmd->segment_active_index < 0 || dmd->segment_active_index >= dmd->segments_len) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (dmd->segments_len == 1) {
+ MEM_SAFE_FREE(dmd->segments);
+ dmd->segment_active_index = -1;
+ }
+ else {
+ DashGpencilModifierSegment *new_segments = MEM_malloc_arrayN(
+ dmd->segments_len, sizeof(DashGpencilModifierSegment), __func__);
+
+ /* Copy the segments before the deleted segment. */
+ memcpy(new_segments,
+ dmd->segments,
+ sizeof(DashGpencilModifierSegment) * dmd->segment_active_index);
+
+ /* Copy the segments after the deleted segment. */
+ memcpy(new_segments + dmd->segment_active_index,
+ dmd->segments + dmd->segment_active_index + 1,
+ sizeof(DashGpencilModifierSegment) *
+ (dmd->segments_len - dmd->segment_active_index - 1));
+
+ MEM_freeN(dmd->segments);
+ dmd->segments = new_segments;
+ dmd->segment_active_index = MAX2(dmd->segment_active_index - 1, 0);
+ }
+
+ dmd->segments_len--;
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int dash_segment_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op, NULL, NULL)) {
+ return dash_segment_remove_exec(C, op);
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void GPENCIL_OT_segment_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Dash Segment";
+ ot->description = "Remove the active segment from the dash modifier";
+ ot->idname = "GPENCIL_OT_segment_remove";
+
+ /* api callbacks */
+ ot->poll = dash_segment_poll;
+ ot->invoke = dash_segment_remove_invoke;
+ ot->exec = dash_segment_remove_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+
+ RNA_def_int(
+ ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of the segment to remove", 0, INT_MAX);
+}
+
+enum {
+ GP_SEGEMENT_MOVE_UP = -1,
+ GP_SEGEMENT_MOVE_DOWN = 1,
+};
+
+static int dash_segment_move_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+
+ DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
+ op, ob, eGpencilModifierType_Dash);
+
+ if (dmd->segments_len < 2) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const int direction = RNA_enum_get(op->ptr, "type");
+ if (direction == GP_SEGEMENT_MOVE_UP) {
+ if (dmd->segment_active_index == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SWAP(DashGpencilModifierSegment,
+ dmd->segments[dmd->segment_active_index],
+ dmd->segments[dmd->segment_active_index - 1]);
+
+ dmd->segment_active_index--;
+ }
+ else if (direction == GP_SEGEMENT_MOVE_DOWN) {
+ if (dmd->segment_active_index == dmd->segments_len - 1) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SWAP(DashGpencilModifierSegment,
+ dmd->segments[dmd->segment_active_index],
+ dmd->segments[dmd->segment_active_index + 1]);
+
+ dmd->segment_active_index++;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int dash_segment_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op, NULL, NULL)) {
+ return dash_segment_move_exec(C, op);
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void GPENCIL_OT_segment_move(wmOperatorType *ot)
+{
+ static const EnumPropertyItem segment_move[] = {
+ {GP_SEGEMENT_MOVE_UP, "UP", 0, "Up", ""},
+ {GP_SEGEMENT_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Move Dash Segment";
+ ot->description = "Move the active dash segment up or down";
+ ot->idname = "GPENCIL_OT_segment_move";
+
+ /* api callbacks */
+ ot->poll = dash_segment_poll;
+ ot->invoke = dash_segment_move_invoke;
+ ot->exec = dash_segment_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+
+ ot->prop = RNA_def_enum(ot->srna, "type", segment_move, 0, "Type", "");
+}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 10e016738d0..50dd9322c5c 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -191,6 +191,7 @@ void OBJECT_OT_skin_radii_equalize(struct wmOperatorType *ot);
void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot);
void OBJECT_OT_laplaciandeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_surfacedeform_bind(struct wmOperatorType *ot);
+void OBJECT_OT_geometry_nodes_input_attribute_toggle(struct wmOperatorType *ot);
/* object_gpencil_modifiers.c */
void OBJECT_OT_gpencil_modifier_add(struct wmOperatorType *ot);
@@ -202,6 +203,10 @@ void OBJECT_OT_gpencil_modifier_apply(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_copy_to_selected(struct wmOperatorType *ot);
+void GPENCIL_OT_segment_add(struct wmOperatorType *ot);
+void GPENCIL_OT_segment_remove(struct wmOperatorType *ot);
+void GPENCIL_OT_segment_move(struct wmOperatorType *ot);
+
/* object_shader_fx.c */
void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot);
void OBJECT_OT_shaderfx_copy(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index e1e0a0600be..b9942bc563a 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -3100,7 +3100,7 @@ void OBJECT_OT_ocean_bake(wmOperatorType *ot)
/** \} */
/* ------------------------------------------------------------------- */
-/** \name Laplaciandeform Bind Operator
+/** \name Laplacian-Deform Bind Operator
* \{ */
static bool laplaciandeform_poll(bContext *C)
@@ -3242,3 +3242,54 @@ void OBJECT_OT_surfacedeform_bind(wmOperatorType *ot)
}
/** \} */
+
+/* ------------------------------------------------------------------- */
+/** \name Toggle Value or Attribute Operator
+ *
+ * \note This operator basically only exists to provide a better tooltip for the toggle button,
+ * since it is stored as an IDProperty. It also stops the button from being highlighted when
+ * "use_attribute" is on, which isn't expected.
+ * \{ */
+
+static int geometry_nodes_input_attribute_toggle_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+
+ char modifier_name[MAX_NAME];
+ RNA_string_get(op->ptr, "modifier_name", modifier_name);
+ NodesModifierData *nmd = (NodesModifierData *)BKE_modifiers_findby_name(ob, modifier_name);
+ if (nmd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ char prop_path[MAX_NAME];
+ RNA_string_get(op->ptr, "prop_path", prop_path);
+
+ PointerRNA mod_ptr;
+ RNA_pointer_create(&ob->id, &RNA_Modifier, nmd, &mod_ptr);
+
+ const int old_value = RNA_int_get(&mod_ptr, prop_path);
+ const int new_value = !old_value;
+ RNA_int_set(&mod_ptr, prop_path, new_value);
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_geometry_nodes_input_attribute_toggle(wmOperatorType *ot)
+{
+ ot->name = "Input Attribute Toggle";
+ ot->description =
+ "Switch between an attribute and a single value to define the data for every element";
+ ot->idname = "OBJECT_OT_geometry_nodes_input_attribute_toggle";
+
+ ot->exec = geometry_nodes_input_attribute_toggle_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_string(ot->srna, "prop_path", NULL, 0, "Prop Path", "");
+ RNA_def_string(ot->srna, "modifier_name", NULL, MAX_NAME, "Modifier Name", "");
+}
+
+/** \} */
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index c1928cf7f8a..aa9ae082317 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -145,6 +145,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_skin_loose_mark_clear);
WM_operatortype_append(OBJECT_OT_skin_radii_equalize);
WM_operatortype_append(OBJECT_OT_skin_armature_create);
+ WM_operatortype_append(OBJECT_OT_geometry_nodes_input_attribute_toggle);
/* grease pencil modifiers */
WM_operatortype_append(OBJECT_OT_gpencil_modifier_add);
@@ -156,6 +157,10 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy);
WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy_to_selected);
+ WM_operatortype_append(GPENCIL_OT_segment_add);
+ WM_operatortype_append(GPENCIL_OT_segment_remove);
+ WM_operatortype_append(GPENCIL_OT_segment_move);
+
/* grease pencil line art */
WM_operatortypes_lineart();
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 699efd9ce75..2d535b12b08 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -87,6 +87,7 @@
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_pointcloud.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -94,7 +95,6 @@
#include "BKE_speaker.h"
#include "BKE_texture.h"
#include "BKE_volume.h"
-#include "BKE_paint.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -2734,90 +2734,94 @@ char *ED_object_ot_drop_named_material_tooltip(bContext *C,
PointerRNA *properties,
const wmEvent *event)
{
- Object *ob = ED_view3d_give_object_under_cursor(C, event->mval);
+ int mat_slot = 0;
+ Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot);
if (ob == NULL) {
return BLI_strdup("");
}
+ mat_slot = max_ii(mat_slot, 1);
char name[MAX_ID_NAME - 2];
RNA_string_get(properties, "name", name);
- int active_mat_slot = max_ii(ob->actcol, 1);
- Material *prev_mat = BKE_object_material_get(ob, active_mat_slot);
+ Material *prev_mat = BKE_object_material_get(ob, mat_slot);
char *result;
if (prev_mat) {
const char *tooltip = TIP_("Drop %s on %s (slot %d, replacing %s)");
- result = BLI_sprintfN(tooltip, name, ob->id.name + 2, active_mat_slot, prev_mat->id.name + 2);
+ result = BLI_sprintfN(tooltip, name, ob->id.name + 2, mat_slot, prev_mat->id.name + 2);
}
else {
const char *tooltip = TIP_("Drop %s on %s (slot %d)");
- result = BLI_sprintfN(tooltip, name, ob->id.name + 2, active_mat_slot);
+ result = BLI_sprintfN(tooltip, name, ob->id.name + 2, mat_slot);
}
return result;
}
-static void drop_named_material_face_set_slots_update(bContext *C, Object *ob, const wmEvent *event) {
- Main *bmain = CTX_data_main(C);
- Mesh *mesh = BKE_mesh_from_object(ob);
+static void drop_named_material_face_set_slots_update(bContext *C,
+ Object *ob,
+ const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ Mesh *mesh = BKE_mesh_from_object(ob);
- bScreen *screen = CTX_wm_screen(C);
- ARegion *region = BKE_screen_find_main_region_at_xy(
- screen, SPACE_VIEW3D, event->x, event->y);
+ bScreen *screen = CTX_wm_screen(C);
+ ARegion *region = BKE_screen_find_main_region_at_xy(screen, SPACE_VIEW3D, event->x, event->y);
- const float mval[2] = {event->x - region->winrct.xmin, event->y - region->winrct.ymin};
- const int face_set_id = ED_sculpt_face_sets_active_update_and_get(C, ob, mval);
+ const float mval[2] = {event->x - region->winrct.xmin, event->y - region->winrct.ymin};
+ const int face_set_id = ED_sculpt_face_sets_active_update_and_get(C, ob, mval);
- int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
+ int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
- short face_set_nr = -1;
- for (int i = 0; i < mesh->totpoly; i++) {
- if (face_sets[i] != face_set_id) {
- continue;
- }
- face_set_nr = mesh->mpoly[i].mat_nr;
- break;
+ short face_set_nr = -1;
+ for (int i = 0; i < mesh->totpoly; i++) {
+ if (face_sets[i] != face_set_id) {
+ continue;
}
+ face_set_nr = mesh->mpoly[i].mat_nr;
+ break;
+ }
- bool create_new_slot = false;
- for (int i = 0; i < mesh->totpoly; i++) {
- if (face_sets[i] == face_set_id) {
- if (mesh->mpoly[i].mat_nr != face_set_nr) {
- create_new_slot = true;
- break;
- }
- }
- else {
- if (mesh->mpoly[i].mat_nr == face_set_nr) {
- create_new_slot = true;
- break;
- }
+ bool create_new_slot = false;
+ for (int i = 0; i < mesh->totpoly; i++) {
+ if (face_sets[i] == face_set_id) {
+ if (mesh->mpoly[i].mat_nr != face_set_nr) {
+ create_new_slot = true;
+ break;
}
}
-
-
- if (create_new_slot) {
- BKE_object_material_slot_add(bmain, ob);
- }
else {
- ob->actcol = face_set_nr + 1;
+ if (mesh->mpoly[i].mat_nr == face_set_nr) {
+ create_new_slot = true;
+ break;
+ }
}
+ }
- const short active_mat_slot = ob->actcol;
- const short material_nr = active_mat_slot - 1;
- for (int i = 0; i < mesh->totpoly; i++) {
- if (face_sets[i] != face_set_id) {
- continue;
- }
- mesh->mpoly[i].mat_nr = material_nr;
- }
+ if (create_new_slot) {
+ BKE_object_material_slot_add(bmain, ob);
+ }
+ else {
+ ob->actcol = face_set_nr + 1;
+ }
+ const short active_mat_slot = ob->actcol;
+ const short material_nr = active_mat_slot - 1;
+ for (int i = 0; i < mesh->totpoly; i++) {
+ if (face_sets[i] != face_set_id) {
+ continue;
+ }
+ mesh->mpoly[i].mat_nr = material_nr;
+ }
}
static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
- Object *ob = ED_view3d_give_object_under_cursor(C, event->mval);
+ int mat_slot = 0;
+ Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot);
+ mat_slot = max_ii(mat_slot, 1);
+
Material *ma;
char name[MAX_ID_NAME - 2];
@@ -2831,10 +2835,7 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
drop_named_material_face_set_slots_update(C, ob, event);
}
- const short active_mat_slot = ob->actcol;
-
- BKE_object_material_assign(
- CTX_data_main(C), ob, ma, active_mat_slot, BKE_MAT_ASSIGN_USERPREF);
+ BKE_object_material_assign(CTX_data_main(C), ob, ma, mat_slot, BKE_MAT_ASSIGN_USERPREF);
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index e08a4e946f6..9546035375c 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -882,7 +882,7 @@ static void area_azone_init(wmWindow *win, const bScreen *screen, ScrArea *area)
return;
}
- if (U.app_flag & USER_APP_LOCK_UI_LAYOUT) {
+ if (U.app_flag & USER_APP_LOCK_CORNER_SPLIT) {
return;
}
@@ -1058,6 +1058,14 @@ static bool region_azone_edge_poll(const ARegion *region, const bool is_fullscre
return false;
}
+ if (is_hidden && (U.app_flag & USER_APP_HIDE_REGION_TOGGLE)) {
+ return false;
+ }
+
+ if (!is_hidden && (U.app_flag & USER_APP_LOCK_EDGE_RESIZE)) {
+ return false;
+ }
+
return true;
}
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index b0181de96a0..2ccefb993c7 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -56,6 +56,7 @@
#include "ED_armature.h"
#include "ED_gpencil.h"
+#include "SEQ_select.h"
#include "SEQ_sequencer.h"
#include "UI_interface.h"
@@ -91,10 +92,13 @@ const char *screen_context_dir[] = {
"image_paint_object",
"particle_edit_object",
"pose_object",
+ "active_sequence_strip",
"sequences",
"selected_sequences",
"selected_editable_sequences", /* sequencer */
- "selected_nla_strips", /* nla editor */
+ "active_nla_track",
+ "active_nla_strip",
+ "selected_nla_strips", /* nla editor */
"gpencil_data",
"gpencil_data_owner", /* grease pencil data */
"annotation_data",
@@ -603,11 +607,23 @@ static eContextResult screen_ctx_pose_object(const bContext *C, bContextDataResu
}
return CTX_RESULT_OK;
}
+static eContextResult screen_ctx_active_sequence_strip(const bContext *C,
+ bContextDataResult *result)
+{
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = WM_window_get_active_scene(win);
+ Sequence *seq = SEQ_select_active_get(scene);
+ if (seq) {
+ CTX_data_pointer_set(result, &scene->id, &RNA_Sequence, seq);
+ return CTX_RESULT_OK;
+ }
+ return CTX_RESULT_NO_DATA;
+}
static eContextResult screen_ctx_sequences(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (ed) {
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
CTX_data_list_add(result, &scene->id, &RNA_Sequence, seq);
@@ -621,7 +637,7 @@ static eContextResult screen_ctx_selected_sequences(const bContext *C, bContextD
{
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (ed) {
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
if (seq->flag & SELECT) {
@@ -638,7 +654,7 @@ static eContextResult screen_ctx_selected_editable_sequences(const bContext *C,
{
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (ed) {
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
if (seq->flag & SELECT && !(seq->flag & SEQ_LOCK)) {
@@ -650,6 +666,24 @@ static eContextResult screen_ctx_selected_editable_sequences(const bContext *C,
}
return CTX_RESULT_NO_DATA;
}
+static eContextResult screen_ctx_active_nla_track(const bContext *C, bContextDataResult *result)
+{
+ PointerRNA ptr;
+ if (ANIM_nla_context_track_ptr(C, &ptr)) {
+ CTX_data_pointer_set_ptr(result, &ptr);
+ return CTX_RESULT_OK;
+ }
+ return CTX_RESULT_NO_DATA;
+}
+static eContextResult screen_ctx_active_nla_strip(const bContext *C, bContextDataResult *result)
+{
+ PointerRNA ptr;
+ if (ANIM_nla_context_strip_ptr(C, &ptr)) {
+ CTX_data_pointer_set_ptr(result, &ptr);
+ return CTX_RESULT_OK;
+ }
+ return CTX_RESULT_NO_DATA;
+}
static eContextResult screen_ctx_selected_nla_strips(const bContext *C, bContextDataResult *result)
{
bAnimContext ac;
@@ -707,7 +741,7 @@ static eContextResult screen_ctx_gpencil_data_owner(const bContext *C, bContextD
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(area, obact, &ptr);
if (gpd_ptr) {
- CTX_data_pointer_set(result, ptr.owner_id, ptr.type, ptr.data);
+ CTX_data_pointer_set_ptr(result, &ptr);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
@@ -739,7 +773,7 @@ static eContextResult screen_ctx_annotation_data_owner(const bContext *C,
bGPdata **gpd_ptr = ED_annotation_data_get_pointers_direct((ID *)screen, area, scene, &ptr);
if (gpd_ptr) {
- CTX_data_pointer_set(result, ptr.owner_id, ptr.type, ptr.data);
+ CTX_data_pointer_set_ptr(result, &ptr);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
@@ -1097,9 +1131,12 @@ static void ensure_ed_screen_context_functions(void)
register_context_function("image_paint_object", screen_ctx_image_paint_object);
register_context_function("particle_edit_object", screen_ctx_particle_edit_object);
register_context_function("pose_object", screen_ctx_pose_object);
+ register_context_function("active_sequence_strip", screen_ctx_active_sequence_strip);
register_context_function("sequences", screen_ctx_sequences);
register_context_function("selected_sequences", screen_ctx_selected_sequences);
register_context_function("selected_editable_sequences", screen_ctx_selected_editable_sequences);
+ register_context_function("active_nla_track", screen_ctx_active_nla_track);
+ register_context_function("active_nla_strip", screen_ctx_active_nla_strip);
register_context_function("selected_nla_strips", screen_ctx_selected_nla_strips);
register_context_function("gpencil_data", screen_ctx_gpencil_data);
register_context_function("gpencil_data_owner", screen_ctx_gpencil_data_owner);
diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c
index 51edad0332b..e67c933cb8e 100644
--- a/source/blender/editors/screen/screen_geometry.c
+++ b/source/blender/editors/screen/screen_geometry.c
@@ -130,6 +130,10 @@ ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const int mx,
const int my)
{
+ if (U.app_flag & USER_APP_LOCK_EDGE_RESIZE) {
+ return NULL;
+ }
+
/* Use layout size (screen excluding global areas) for screen-layout area edges */
rcti screen_rect;
WM_window_screen_rect_calc(win, &screen_rect);
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 683f2844371..4016ef84bfd 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -128,6 +128,7 @@ extern const char *screen_context_dir[]; /* doc access */
/* screendump.c */
void SCREEN_OT_screenshot(struct wmOperatorType *ot);
+void SCREEN_OT_screenshot_area(struct wmOperatorType *ot);
/* workspace_layout_edit.c */
bool workspace_layout_set_poll(const struct WorkSpaceLayout *layout);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index daac196a90c..674a2deb929 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -1134,14 +1134,22 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
if ((ED_area_actionzone_find_xy(sad->sa1, &event->x) != sad->az) &&
(screen_geom_area_map_find_active_scredge(
AREAMAP_FROM_SCREEN(screen), &screen_rect, event->x, event->y) == NULL)) {
- /* Are we still in same area? */
- if (BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) {
+
+ /* What area are we now in? */
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
+
+ if (area == sad->sa1) {
/* Same area, so possible split. */
WM_cursor_set(win,
SCREEN_DIR_IS_VERTICAL(sad->gesture_dir) ? WM_CURSOR_H_SPLIT :
WM_CURSOR_V_SPLIT);
is_gesture = (delta_max > split_threshold);
}
+ else if (!area || area->global) {
+ /* No area or Top bar or Status bar. */
+ WM_cursor_set(win, WM_CURSOR_STOP);
+ is_gesture = false;
+ }
else {
/* Different area, so possible join. */
if (sad->gesture_dir == SCREEN_DIR_N) {
@@ -1161,7 +1169,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else {
- WM_cursor_set(CTX_wm_window(C), WM_CURSOR_CROSS);
+ WM_cursor_set(win, WM_CURSOR_CROSS);
is_gesture = false;
}
}
@@ -1466,15 +1474,39 @@ static void SCREEN_OT_area_dupli(wmOperatorType *ot)
* Close selected area, replace by expanding a neighbor
* \{ */
-/* operator callback */
-static int area_close_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+/**
+ * \note This can be used interactively or from Python.
+ *
+ * \note Most of the window management operators don't support execution from Python.
+ * An exception is made for closing areas since it allows application templates
+ * to customize the layout.
+ */
+static int area_close_exec(bContext *C, wmOperator *op)
{
+ bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
- if ((area != NULL) && screen_area_close(C, CTX_wm_screen(C), area)) {
- WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+
+ /* This operator is scriptable, so the area passed could be invalid. */
+ if (BLI_findindex(&screen->areabase, area) == -1) {
+ BKE_report(op->reports, RPT_ERROR, "Area not found in the active screen");
+ return OPERATOR_CANCELLED;
}
- return OPERATOR_CANCELLED;
+
+ if (!screen_area_close(C, screen, area)) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to close area");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Ensure the event loop doesn't attempt to continue handling events.
+ *
+ * This causes execution from the Python console fail to return to the prompt as it should.
+ * This glitch could be solved in the event loop handling as other operators may also
+ * destructively manipulate windowing data. */
+ CTX_wm_window_set(C, NULL);
+
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
static bool area_close_poll(bContext *C)
@@ -1506,7 +1538,7 @@ static void SCREEN_OT_area_close(wmOperatorType *ot)
ot->name = "Close Area";
ot->description = "Close selected area";
ot->idname = "SCREEN_OT_area_close";
- ot->invoke = area_close_invoke;
+ ot->exec = area_close_exec;
ot->poll = area_close_poll;
}
@@ -3075,6 +3107,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
mask_to_keylist(&ads, masklay, keylist);
}
}
+ ED_keylist_prepare_for_direct_access(keylist);
/* find matching keyframe in the right direction */
const ActKeyColumn *ak;
@@ -5657,6 +5690,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_back_to_previous);
WM_operatortype_append(SCREEN_OT_spacedata_cleanup);
WM_operatortype_append(SCREEN_OT_screenshot);
+ WM_operatortype_append(SCREEN_OT_screenshot_area);
WM_operatortype_append(SCREEN_OT_userpref_show);
WM_operatortype_append(SCREEN_OT_drivers_editor_show);
WM_operatortype_append(SCREEN_OT_info_log_show);
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 6df96b1e30f..8056e02d17a 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -42,6 +42,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_screen.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -57,12 +58,13 @@ typedef struct ScreenshotData {
uint *dumprect;
int dumpsx, dumpsy;
rcti crop;
+ bool use_crop;
ImageFormatData im_format;
} ScreenshotData;
/* call from both exec and invoke */
-static int screenshot_data_create(bContext *C, wmOperator *op)
+static int screenshot_data_create(bContext *C, wmOperator *op, ScrArea *area)
{
int dumprect_size[2];
@@ -76,7 +78,6 @@ static int screenshot_data_create(bContext *C, wmOperator *op)
if (dumprect) {
ScreenshotData *scd = MEM_callocN(sizeof(ScreenshotData), "screenshot");
- ScrArea *area = CTX_wm_area(C);
scd->dumpsx = dumprect_size[0];
scd->dumpsy = dumprect_size[1];
@@ -110,12 +111,13 @@ static void screenshot_data_free(wmOperator *op)
static int screenshot_exec(bContext *C, wmOperator *op)
{
+ const bool use_crop = STREQ(op->idname, "SCREEN_OT_screenshot_area");
ScreenshotData *scd = op->customdata;
bool ok = false;
if (scd == NULL) {
/* when running exec directly */
- screenshot_data_create(C, op);
+ screenshot_data_create(C, op, use_crop ? CTX_wm_area(C) : NULL);
scd = op->customdata;
}
@@ -132,7 +134,7 @@ static int screenshot_exec(bContext *C, wmOperator *op)
ibuf->rect = scd->dumprect;
/* crop to show only single editor */
- if (!RNA_boolean_get(op->ptr, "full")) {
+ if (use_crop) {
IMB_rect_crop(ibuf, &scd->crop);
scd->dumprect = ibuf->rect;
}
@@ -157,9 +159,20 @@ static int screenshot_exec(bContext *C, wmOperator *op)
return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
-static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- if (screenshot_data_create(C, op)) {
+ const bool use_crop = STREQ(op->idname, "SCREEN_OT_screenshot_area");
+ ScrArea *area = NULL;
+ if (use_crop) {
+ area = CTX_wm_area(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area_test = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
+ if (area_test != NULL) {
+ area = area_test;
+ }
+ }
+
+ if (screenshot_data_create(C, op, area)) {
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
return screenshot_exec(C, op);
}
@@ -226,12 +239,8 @@ static bool screenshot_poll(bContext *C)
return WM_operator_winactive(C);
}
-void SCREEN_OT_screenshot(wmOperatorType *ot)
+static void screen_screenshot_impl(wmOperatorType *ot)
{
- ot->name = "Save Screenshot";
- ot->idname = "SCREEN_OT_screenshot";
- ot->description = "Capture a picture of the active area or whole Blender window";
-
ot->invoke = screenshot_invoke;
ot->check = screenshot_check;
ot->exec = screenshot_exec;
@@ -239,8 +248,6 @@ void SCREEN_OT_screenshot(wmOperatorType *ot)
ot->ui = screenshot_draw;
ot->poll = screenshot_poll;
- ot->flag = 0;
-
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE,
FILE_SPECIAL,
@@ -248,9 +255,26 @@ void SCREEN_OT_screenshot(wmOperatorType *ot)
WM_FILESEL_FILEPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
- RNA_def_boolean(ot->srna,
- "full",
- 1,
- "Full Screen",
- "Capture the whole window (otherwise only capture the active area)");
+}
+
+void SCREEN_OT_screenshot(wmOperatorType *ot)
+{
+ ot->name = "Save Screenshot";
+ ot->idname = "SCREEN_OT_screenshot";
+ ot->description = "Capture a picture of the whole Blender window";
+
+ screen_screenshot_impl(ot);
+
+ ot->flag = 0;
+}
+
+void SCREEN_OT_screenshot_area(wmOperatorType *ot)
+{
+ ot->name = "Save Screenshot (Area)";
+ ot->idname = "SCREEN_OT_screenshot_area";
+ ot->description = "Capture a picture of the active area";
+
+ screen_screenshot_impl(ot);
+
+ ot->flag = OPTYPE_DEPENDS_ON_CURSOR;
}
diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c
index 31ca11bb847..0ec32da0404 100644
--- a/source/blender/editors/screen/workspace_layout_edit.c
+++ b/source/blender/editors/screen/workspace_layout_edit.c
@@ -140,7 +140,7 @@ bool ED_workspace_layout_delete(WorkSpace *workspace, WorkSpaceLayout *layout_ol
BLI_assert(BLI_findindex(&workspace->layouts, layout_old) != -1);
- /* don't allow deleting temp fullscreens for now */
+ /* Don't allow deleting temp full-screens for now. */
if (BKE_screen_is_fullscreen_area(screen_old)) {
return false;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 39d776e0054..b5113681955 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -1153,7 +1153,7 @@ void ED_object_texture_paint_mode_enter_ex(Main *bmain, Scene *scene, Object *ob
SpaceImage *sima = (SpaceImage *)sl;
if (!sima->pin) {
- ED_space_image_set(bmain, sima, NULL, ima, true);
+ ED_space_image_set(bmain, sima, ima, true);
}
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index b8e0e2eac61..a0f4bac2e7c 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -1342,7 +1342,7 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
}),
sculpt_mesh);
BM_mesh_free(bm);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
BKE_mesh_nomain_to_mesh(
result, sgcontext->vc.obact->data, sgcontext->vc.obact, &CD_MASK_MESH, true);
}
@@ -1896,7 +1896,7 @@ void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot)
ot->poll = SCULPT_mode_poll_view3d;
- ot->flag = OPTYPE_REGISTER;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_DEPENDS_ON_CURSOR;
/* Properties. */
WM_operator_properties_gesture_lasso(ot);
@@ -1959,6 +1959,8 @@ void SCULPT_OT_face_set_lasso_gesture(wmOperatorType *ot)
ot->poll = SCULPT_mode_poll_view3d;
+ ot->flag = OPTYPE_DEPENDS_ON_CURSOR;
+
/* Properties. */
WM_operator_properties_gesture_lasso(ot);
sculpt_gesture_operator_properties(ot);
@@ -1995,7 +1997,7 @@ void SCULPT_OT_trim_lasso_gesture(wmOperatorType *ot)
ot->poll = SCULPT_mode_poll_view3d;
- ot->flag = OPTYPE_REGISTER;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_DEPENDS_ON_CURSOR;
/* Properties. */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 6f4e295cbb2..3e38be243c9 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -192,7 +192,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
bGPDlayer *gpl = ale->data;
bGPDframe *gpf;
- /* find gp-frame which is less than or equal to cframe */
+ /* Find gp-frame which is less than or equal to current-frame. */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
const float framenum = (float)gpf->framenum;
*min = min_ff(*min, framenum);
@@ -204,7 +204,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
MaskLayer *masklay = ale->data;
MaskLayerShape *masklay_shape;
- /* find mask layer which is less than or equal to cframe */
+ /* Find mask layer which is less than or equal to current-frame. */
for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
masklay_shape = masklay_shape->next) {
const float framenum = (float)masklay_shape->frame;
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 9dcfc626a50..26d71178b68 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -162,6 +162,7 @@ static void actkeys_find_key_in_list_element(bAnimContext *ac,
struct AnimKeylist *keylist = ED_keylist_create();
actkeys_list_element_to_keylist(ac, keylist, ale);
+ ED_keylist_prepare_for_direct_access(keylist);
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
@@ -833,7 +834,7 @@ void ACTION_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 5e5143723a6..f59429ba981 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -536,9 +536,9 @@ static void action_listener(const wmSpaceTypeListenerParams *params)
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
ED_area_tag_refresh(area);
}
- /* autocolor only really needs to change when channels are added/removed,
+ /* Auto-color only really needs to change when channels are added/removed,
* or previously hidden stuff appears
- * (assume for now that if just adding these works, that will be fine)
+ * (assume for now that if just adding these works, that will be fine).
*/
else if (((wmn->data == ND_KEYFRAME) && ELEM(wmn->action, NA_ADDED, NA_REMOVED)) ||
((wmn->data == ND_ANIMCHAN) && (wmn->action != NA_SELECTED))) {
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index bf855db07e9..91b0677ebaa 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -72,7 +72,7 @@ static int set_pointer_type(ButsContextPath *path, bContextDataResult *result, S
PointerRNA *ptr = &path->ptr[i];
if (RNA_struct_is_a(ptr->type, type)) {
- CTX_data_pointer_set(result, ptr->owner_id, ptr->type, ptr->data);
+ CTX_data_pointer_set_ptr(result, ptr);
return CTX_RESULT_OK;
}
}
@@ -1003,7 +1003,7 @@ int /*eContextResult*/ buttons_context(const bContext *C,
if (ct->user && ct->user->ptr.data) {
ButsTextureUser *user = ct->user;
- CTX_data_pointer_set(result, user->ptr.owner_id, user->ptr.type, user->ptr.data);
+ CTX_data_pointer_set_ptr(result, &user->ptr);
}
return CTX_RESULT_OK;
@@ -1092,7 +1092,7 @@ int /*eContextResult*/ buttons_context(const bContext *C,
PointerRNA *ptr = get_pointer_type(path, &RNA_ParticleSettings);
if (ptr && ptr->data) {
- CTX_data_pointer_set(result, ptr->owner_id, &RNA_ParticleSettings, ptr->data);
+ CTX_data_pointer_set_ptr(result, ptr);
return CTX_RESULT_OK;
}
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index c7f0f4c228f..73a73eb7911 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -721,7 +721,7 @@ void CLIP_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 17749d36418..905c0aeb8e0 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -92,6 +92,9 @@ void file_sfile_to_operator(struct Main *bmain, struct wmOperator *op, struct Sp
void file_operator_to_sfile(struct Main *bmain, struct SpaceFile *sfile, struct wmOperator *op);
+/* space_file.c */
+extern const char *file_context_dir[]; /* doc access */
+
/* filesel.c */
void fileselect_refresh_params(struct SpaceFile *sfile);
void fileselect_file_set(SpaceFile *sfile, const int index);
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index c7d23943b6c..511b5b255e9 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1442,7 +1442,9 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
if (preview->in_memory_preview) {
if (BKE_previewimg_is_finished(preview->in_memory_preview, ICON_SIZE_PREVIEW)) {
ImBuf *imbuf = BKE_previewimg_to_imbuf(preview->in_memory_preview, ICON_SIZE_PREVIEW);
- preview->icon_id = BKE_icon_imbuf_create(imbuf);
+ if (imbuf) {
+ preview->icon_id = BKE_icon_imbuf_create(imbuf);
+ }
done = true;
}
}
@@ -1953,7 +1955,9 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in
if (entry->local_data.preview_image &&
BKE_previewimg_is_finished(entry->local_data.preview_image, ICON_SIZE_PREVIEW)) {
ImBuf *ibuf = BKE_previewimg_to_imbuf(entry->local_data.preview_image, ICON_SIZE_PREVIEW);
- ret->preview_icon_id = BKE_icon_imbuf_create(ibuf);
+ if (ibuf) {
+ ret->preview_icon_id = BKE_icon_imbuf_create(ibuf);
+ }
}
BLI_addtail(&cache->cached_entries, ret);
return ret;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 4ab7014cf82..11b06d2b414 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -135,7 +135,8 @@ static void fileselect_ensure_updated_asset_params(SpaceFile *sfile)
base_params->filter_id = FILTER_ID_OB | FILTER_ID_GR;
base_params->display = FILE_IMGDISPLAY;
base_params->sort = FILE_SORT_ALPHA;
- base_params->recursion_level = 1;
+ /* Asset libraries include all sub-directories, so enable maximal recursion. */
+ base_params->recursion_level = FILE_SELECT_MAX_RECURSIONS;
/* 'SMALL' size by default. More reasonable since this is typically used as regular editor,
* space is more of an issue here. */
base_params->thumbnail_size = 96;
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 7deaa2fec60..a4f36c2a6ee 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -871,8 +871,9 @@ static void file_space_subtype_item_extend(bContext *UNUSED(C),
RNA_enum_items_add(item, totitem, rna_enum_space_file_browse_mode_items);
}
-static const char *file_context_dir[] = {
+const char *file_context_dir[] = {
"active_file",
+ "selected_files",
"asset_library_ref",
"id",
NULL,
@@ -907,6 +908,20 @@ static int /*eContextResult*/ file_context(const bContext *C,
CTX_data_pointer_set(result, &screen->id, &RNA_FileSelectEntry, file);
return CTX_RESULT_OK;
}
+ if (CTX_data_equals(member, "selected_files")) {
+ const int num_files_filtered = filelist_files_ensure(sfile->files);
+
+ for (int file_index = 0; file_index < num_files_filtered; file_index++) {
+ if (filelist_entry_is_selected(sfile->files, file_index)) {
+ FileDirEntry *entry = filelist_file(sfile->files, file_index);
+ CTX_data_list_add(result, &screen->id, &RNA_FileSelectEntry, entry);
+ }
+ }
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return CTX_RESULT_OK;
+ }
+
if (CTX_data_equals(member, "asset_library_ref")) {
FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
if (!asset_params) {
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index a853efb1ace..ffe74e20bdf 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -1006,7 +1006,7 @@ void GRAPH_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* Flags. */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* Properties. */
WM_operator_properties_gesture_lasso(ot);
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 10629caa8b0..f04336cab84 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -41,6 +41,7 @@
#include "ED_keyframes_edit.h"
#include "ED_numinput.h"
#include "ED_screen.h"
+#include "ED_util.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -94,6 +95,8 @@ typedef struct tDecimateGraphOp {
/** The original bezt curve data (used for restoring fcurves). */
ListBase bezt_arr_list;
+ struct tSlider *slider;
+
NumInput num;
} tDecimateGraphOp;
@@ -161,6 +164,8 @@ static void decimate_exit(bContext *C, wmOperator *op)
ScrArea *area = dgo->area;
LinkData *link;
+ ED_slider_destroy(C, dgo->slider);
+
for (link = dgo->bezt_arr_list.first; link != NULL; link = link->next) {
tBeztCopyData *copy = link->data;
MEM_freeN(copy->bezt);
@@ -178,11 +183,14 @@ static void decimate_exit(bContext *C, wmOperator *op)
op->customdata = NULL;
}
-/* Draw a percentage indicator in header. */
-static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo)
+/* Draw a percentage indicator in workspace footer. */
+static void decimate_draw_status(bContext *C, tDecimateGraphOp *dgo)
{
char status_str[UI_MAX_DRAW_STR];
char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
+
+ ED_slider_status_string_get(dgo->slider, slider_string, UI_MAX_DRAW_STR);
strcpy(mode_str, TIP_("Decimate Keyframes"));
@@ -194,23 +202,10 @@ static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo)
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
else {
- float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop);
- BLI_snprintf(
- status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(percentage * 100.0f));
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
}
- ED_area_status_text(dgo->area, status_str);
-}
-
-/* Calculate percentage based on position of mouse (we only use x-axis for now.
- * Since this is more convenient for users to do), and store new percentage value.
- */
-static void decimate_mouse_update_percentage(tDecimateGraphOp *dgo,
- wmOperator *op,
- const wmEvent *event)
-{
- float percentage = (event->x - dgo->region->winrct.xmin) / ((float)dgo->region->winx);
- RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage);
+ ED_workspace_status_text(C, status_str);
}
static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -234,10 +229,11 @@ static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent
dgo->area = CTX_wm_area(C);
dgo->region = CTX_wm_region(C);
- /* Initialize percentage so that it will have the correct value before the first mouse move. */
- decimate_mouse_update_percentage(dgo, op, event);
+ dgo->slider = ED_slider_create(C);
+ ED_slider_init(dgo->slider, event);
+ ED_slider_allow_overshoot_set(dgo->slider, false);
- decimate_draw_status_header(op, dgo);
+ decimate_draw_status(C, dgo);
/* Construct a list with the original bezt arrays so we can restore them during modal operation.
*/
@@ -300,13 +296,14 @@ static void graphkeys_decimate_modal_update(bContext *C, wmOperator *op)
* (e.g. pressing a key or moving the mouse). */
tDecimateGraphOp *dgo = op->customdata;
- decimate_draw_status_header(op, dgo);
+ decimate_draw_status(C, dgo);
/* Reset keyframe data (so we get back to the original state). */
decimate_reset_bezts(dgo);
/* Apply... */
- float remove_ratio = RNA_property_float_get(op->ptr, dgo->percentage_prop);
+ float remove_ratio = ED_slider_factor_get(dgo->slider);
+ RNA_property_float_set(op->ptr, dgo->percentage_prop, remove_ratio);
/* We don't want to limit the decimation to a certain error margin. */
const float error_sq_max = FLT_MAX;
decimate_graph_keys(&dgo->ac, remove_ratio, error_sq_max);
@@ -323,6 +320,8 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *
const bool has_numinput = hasNumInput(&dgo->num);
+ ED_slider_modal(dgo->slider, event);
+
switch (event->type) {
case LEFTMOUSE: /* Confirm */
case EVT_RETKEY:
@@ -353,9 +352,6 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *
case MOUSEMOVE: /* Calculate new position. */
{
if (has_numinput == false) {
- /* Update percentage based on position of mouse. */
- decimate_mouse_update_percentage(dgo, op, event);
-
/* Update pose to reflect the new values. */
graphkeys_decimate_modal_update(C, op);
}
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 49966e880d3..720d69eaf4f 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -556,8 +556,8 @@ static void graph_listener(const wmSpaceTypeListenerParams *params)
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
- /* for selection changes of animation data, we can just redraw...
- * otherwise autocolor might need to be done again */
+ /* For selection changes of animation data, we can just redraw...
+ * otherwise auto-color might need to be done again. */
if (ELEM(wmn->data, ND_KEYFRAME, ND_ANIMCHAN) && (wmn->action == NA_SELECTED)) {
ED_area_tag_redraw(area);
}
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index a95189a303f..2174a4b9dc1 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -57,7 +57,7 @@ Image *ED_space_image(SpaceImage *sima)
return sima->image;
}
-void ED_space_image_set(Main *bmain, SpaceImage *sima, Object *obedit, Image *ima, bool automatic)
+void ED_space_image_set(Main *bmain, SpaceImage *sima, Image *ima, bool automatic)
{
/* Automatically pin image when manually assigned, otherwise it follows object. */
if (!automatic && sima->image != ima && sima->mode == SI_MODE_UV) {
@@ -78,10 +78,6 @@ void ED_space_image_set(Main *bmain, SpaceImage *sima, Object *obedit, Image *im
id_us_ensure_real((ID *)sima->image);
- if (obedit) {
- WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
- }
-
WM_main_add_notifier(NC_SPACE | ND_SPACE_IMAGE, NULL);
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 11efd3e33ef..94d44e047a4 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1311,7 +1311,6 @@ static int image_open_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
ImageUser *iuser = NULL;
Image *ima = NULL;
int frame_seq_len = 0;
@@ -1364,7 +1363,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
}
else if (area && area->spacetype == SPACE_IMAGE) {
SpaceImage *sima = area->spacedata.first;
- ED_space_image_set(bmain, sima, obedit, ima, false);
+ ED_space_image_set(bmain, sima, ima, false);
iuser = &sima->iuser;
}
else {
@@ -2519,7 +2518,6 @@ static void image_new_free(wmOperator *op)
static int image_new_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima;
- Object *obedit;
Image *ima;
Main *bmain;
PropertyRNA *prop;
@@ -2531,7 +2529,6 @@ static int image_new_exec(bContext *C, wmOperator *op)
/* retrieve state */
sima = CTX_wm_space_image(C);
- obedit = CTX_data_edit_object(C);
bmain = CTX_data_main(C);
prop = RNA_struct_find_property(op->ptr, "name");
@@ -2587,7 +2584,7 @@ static int image_new_exec(bContext *C, wmOperator *op)
RNA_property_update(C, &data->pprop.ptr, data->pprop.prop);
}
else if (sima) {
- ED_space_image_set(bmain, sima, obedit, ima, false);
+ ED_space_image_set(bmain, sima, ima, false);
}
BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
@@ -3705,7 +3702,7 @@ static int image_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
if (sima->image == NULL) {
- ED_space_image_set(bmain, sima, NULL, ima, false);
+ ED_space_image_set(bmain, sima, ima, false);
}
RE_ReadRenderResult(scene, scene);
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 4107fd619aa..de8e4684d45 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -461,7 +461,7 @@ static void IMAGE_GGT_gizmo2d(wmGizmoGroupType *gzgt)
gzgt->name = "UV Transform Gizmo";
gzgt->idname = "IMAGE_GGT_gizmo2d";
- gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
@@ -475,7 +475,7 @@ static void IMAGE_GGT_gizmo2d_translate(wmGizmoGroupType *gzgt)
gzgt->name = "UV Translate Gizmo";
gzgt->idname = "IMAGE_GGT_gizmo2d_translate";
- gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
@@ -489,7 +489,7 @@ static void IMAGE_GGT_gizmo2d_resize(wmGizmoGroupType *gzgt)
gzgt->name = "UV Transform Gizmo Resize";
gzgt->idname = "IMAGE_GGT_gizmo2d_resize";
- gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
@@ -503,7 +503,7 @@ static void IMAGE_GGT_gizmo2d_rotate(wmGizmoGroupType *gzgt)
gzgt->name = "UV Transform Gizmo Resize";
gzgt->idname = "IMAGE_GGT_gizmo2d_rotate";
- gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index d019573bf93..215e865d194 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -185,10 +185,31 @@ bool nla_panel_context(const bContext *C,
return (found != 0);
}
+bool ANIM_nla_context_track_ptr(const bContext *C, PointerRNA *r_ptr)
+{
+ return nla_panel_context(C, NULL, r_ptr, NULL);
+}
+
+bool ANIM_nla_context_strip_ptr(const bContext *C, PointerRNA *r_ptr)
+{
+ return nla_panel_context(C, NULL, NULL, r_ptr);
+}
+
+NlaTrack *ANIM_nla_context_track(const bContext *C)
+{
+ PointerRNA track_ptr;
+ if (!ANIM_nla_context_track_ptr(C, &track_ptr)) {
+ return NULL;
+ }
+ NlaTrack *track = track_ptr.data;
+
+ return track;
+}
+
NlaStrip *ANIM_nla_context_strip(const bContext *C)
{
PointerRNA strip_ptr;
- if (!nla_panel_context(C, NULL, NULL, &strip_ptr)) {
+ if (!ANIM_nla_context_strip_ptr(C, &strip_ptr)) {
return NULL;
}
NlaStrip *strip = strip_ptr.data;
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index 0f7a911e3ce..4b859de0ac9 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -362,8 +362,12 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
float x = BLI_rctf_cent_x(rct) - (0.5f * width);
float y = rct->ymax - label_height;
- BLF_position(fontid, x, y, 0);
- BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
+ /* label */
+ const bool has_label = node->label[0] != '\0';
+ if (has_label) {
+ BLF_position(fontid, x, y, 0);
+ BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
+ }
/* draw text body */
if (node->id) {
@@ -374,7 +378,8 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
/* 'x' doesn't need aspect correction */
x = rct->xmin + margin;
- y = rct->ymax - (label_height + line_spacing);
+ y = rct->ymax - label_height - (has_label ? line_spacing : 0);
+
/* early exit */
int y_min = y + ((margin * 2) - (y - rct->ymin));
@@ -455,10 +460,8 @@ static void node_draw_frame(const bContext *C,
UI_draw_roundbox_aa(rct, false, BASIS_RAD, color);
}
- /* label */
- if (node->label[0] != '\0') {
- node_draw_frame_label(ntree, node, snode->runtime->aspect);
- }
+ /* label and text */
+ node_draw_frame_label(ntree, node, snode->runtime->aspect);
UI_block_end(C, node->block);
UI_block_draw(C, node->block);
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 9264c9d3572..7b6ca5e6e61 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -312,7 +312,7 @@ void NODE_OT_add_reroute(wmOperatorType *ot)
ot->poll = ED_operator_node_editable;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
PropertyRNA *prop;
@@ -575,7 +575,7 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
bNode *texture_node = node_add_node(C,
nullptr,
- GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE,
+ GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE,
snode->runtime->cursor[0],
snode->runtime->cursor[1]);
if (!texture_node) {
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 5b4e3b3b6f5..aa241071425 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -41,10 +41,12 @@
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
#include "BLT_translation.h"
#include "BKE_context.h"
+#include "BKE_geometry_set.hh"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -78,6 +80,8 @@
#include "NOD_geometry_nodes_eval_log.hh"
+#include "FN_field_cpp_type.hh"
+
#include "node_intern.h" /* own include */
#ifdef WITH_COMPOSITOR
@@ -88,7 +92,11 @@ using blender::Map;
using blender::Set;
using blender::Span;
using blender::Vector;
+using blender::VectorSet;
using blender::fn::CPPType;
+using blender::fn::FieldCPPType;
+using blender::fn::FieldInput;
+using blender::fn::GField;
using blender::fn::GPointer;
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
@@ -850,31 +858,70 @@ static void create_inspection_string_for_generic_value(const geo_log::GenericVal
};
const GPointer value = value_log.value();
- if (value.is_type<int>()) {
- ss << *value.get<int>() << TIP_(" (Integer)");
- }
- else if (value.is_type<float>()) {
- ss << *value.get<float>() << TIP_(" (Float)");
- }
- else if (value.is_type<blender::float3>()) {
- ss << *value.get<blender::float3>() << TIP_(" (Vector)");
- }
- else if (value.is_type<bool>()) {
- ss << (*value.get<bool>() ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
- }
- else if (value.is_type<std::string>()) {
- ss << *value.get<std::string>() << TIP_(" (String)");
+ const CPPType &type = *value.type();
+ if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) {
+ const CPPType &base_type = field_type->field_type();
+ BUFFER_FOR_CPP_TYPE_VALUE(base_type, buffer);
+ const GField &field = field_type->get_gfield(value.get());
+ if (field.node().depends_on_input()) {
+ if (base_type.is<int>()) {
+ ss << TIP_("Integer Field");
+ }
+ else if (base_type.is<float>()) {
+ ss << TIP_("Float Field");
+ }
+ else if (base_type.is<blender::float3>()) {
+ ss << TIP_("Vector Field");
+ }
+ else if (base_type.is<bool>()) {
+ ss << TIP_("Boolean Field");
+ }
+ else if (base_type.is<std::string>()) {
+ ss << TIP_("String Field");
+ }
+ ss << TIP_(" based on:\n");
+
+ /* Use vector set to deduplicate inputs. */
+ VectorSet<std::reference_wrapper<const FieldInput>> field_inputs;
+ field.node().foreach_field_input(
+ [&](const FieldInput &field_input) { field_inputs.add(field_input); });
+ for (const FieldInput &field_input : field_inputs) {
+ ss << "\u2022 " << field_input.socket_inspection_name();
+ if (field_input != field_inputs.as_span().last().get()) {
+ ss << ".\n";
+ }
+ }
+ }
+ else {
+ blender::fn::evaluate_constant_field(field, buffer);
+ if (base_type.is<int>()) {
+ ss << *(int *)buffer << TIP_(" (Integer)");
+ }
+ else if (base_type.is<float>()) {
+ ss << *(float *)buffer << TIP_(" (Float)");
+ }
+ else if (base_type.is<blender::float3>()) {
+ ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
+ }
+ else if (base_type.is<bool>()) {
+ ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
+ }
+ else if (base_type.is<std::string>()) {
+ ss << *(std::string *)buffer << TIP_(" (String)");
+ }
+ base_type.destruct(buffer);
+ }
}
- else if (value.is_type<Object *>()) {
+ else if (type.is<Object *>()) {
id_to_inspection_string((ID *)*value.get<Object *>(), ID_OB);
}
- else if (value.is_type<Material *>()) {
+ else if (type.is<Material *>()) {
id_to_inspection_string((ID *)*value.get<Material *>(), ID_MA);
}
- else if (value.is_type<Tex *>()) {
+ else if (type.is<Tex *>()) {
id_to_inspection_string((ID *)*value.get<Tex *>(), ID_TE);
}
- else if (value.is_type<Collection *>()) {
+ else if (type.is<Collection *>()) {
id_to_inspection_string((ID *)*value.get<Collection *>(), ID_GR);
}
}
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 5b1b737751c..030d1672a08 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -52,6 +52,7 @@
#include "RE_engine.h"
#include "RE_pipeline.h"
+#include "ED_image.h"
#include "ED_node.h" /* own include */
#include "ED_render.h"
#include "ED_screen.h"
@@ -719,11 +720,22 @@ void ED_node_set_active(
ED_node_tag_update_nodetree(bmain, ntree, node);
}
- /* if active texture changed, free glsl materials */
if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
+ /* If active texture changed, free glsl materials. */
LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
if (ma->nodetree && ma->use_nodes && ntreeHasTree(ma->nodetree, ntree)) {
GPU_material_free(&ma->gpumaterial);
+
+ /* Sync to active texpaint slot, otherwise we can end up painting on a different slot
+ * than we are looking at. */
+ if (ma->texpaintslot) {
+ Image *image = (Image *)node->id;
+ for (int i = 0; i < ma->tot_slots; i++) {
+ if (ma->texpaintslot[i].ima == image) {
+ ma->paint_active_slot = i;
+ }
+ }
+ }
}
}
@@ -733,6 +745,23 @@ void ED_node_set_active(
}
}
+ /* Sync to Image Editor. */
+ Image *image = (Image *)node->id;
+ wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+ if (!sima->pin) {
+ ED_space_image_set(bmain, sima, image, true);
+ }
+ }
+ }
+ }
+ }
+
if (r_active_texture_changed) {
*r_active_texture_changed = true;
}
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index e908a61eed9..7d95659e403 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -1427,7 +1427,7 @@ void NODE_OT_links_cut(wmOperatorType *ot)
ot->poll = ED_operator_node_editable;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
PropertyRNA *prop;
@@ -1533,7 +1533,7 @@ void NODE_OT_links_mute(wmOperatorType *ot)
ot->poll = ED_operator_node_editable;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
PropertyRNA *prop;
diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc
index adff85a2b8c..29b8372d043 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -923,7 +923,7 @@ void NODE_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
RNA_def_boolean(ot->srna,
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index db37c8c1c8c..c06a1010168 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -32,6 +32,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_text_types.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -59,6 +60,7 @@
#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
+#include "ED_fileselect.h"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -2625,9 +2627,17 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case ID_NLA:
data.icon = ICON_NLA;
break;
- case ID_TXT:
- data.icon = ICON_SCRIPT;
+ case ID_TXT: {
+ Text *text = (Text *)tselem->id;
+ if (text->filepath == NULL || (text->flags & TXT_ISMEM)) {
+ data.icon = ICON_FILE_TEXT;
+ }
+ else {
+ /* Helps distinguish text-based formats like the file-browser does. */
+ data.icon = ED_file_extension_icon(text->filepath);
+ }
break;
+ }
case ID_GR:
data.icon = ICON_OUTLINER_COLLECTION;
break;
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 1feecc04ead..581892ebb3a 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -673,7 +673,7 @@ static void tree_element_sequence_activate(bContext *C,
const eOLSetState set)
{
Sequence *seq = (Sequence *)te->directdata;
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
if (set == OL_SETSEL_EXTEND) {
@@ -695,7 +695,7 @@ static void tree_element_sequence_activate(bContext *C,
static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED(te))
{
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
#if 0
select_single_seq(seq, 1);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index d88ae82cc9a..9e314701719 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -737,13 +737,8 @@ static void id_local_fn(bContext *C,
{
if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
Main *bmain = CTX_data_main(C);
- /* if the ID type has no special local function,
- * just clear the lib */
- if (BKE_lib_id_make_local(bmain, tselem->id, false, 0) == false) {
- BKE_lib_id_clear_library_data(bmain, tselem->id);
- }
- else {
- BKE_main_id_newptr_and_tag_clear(bmain);
+ if (BKE_lib_id_make_local(bmain, tselem->id, 0)) {
+ BKE_id_newptr_and_tag_clear(tselem->id);
}
}
else if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) {
@@ -1286,7 +1281,7 @@ static void sequence_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem
{
Sequence *seq = (Sequence *)te->directdata;
Scene *scene = (Scene *)scene_ptr;
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
if (event == OL_DOP_SELECT) {
ED_sequencer_select_sequence_single(scene, seq, true);
diff --git a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
index 40f329d72c3..02af6a13cb3 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
@@ -43,7 +43,7 @@ ListBase TreeDisplaySequencer::buildTree(const TreeSourceData &source_data)
{
ListBase tree = {nullptr};
- Editing *ed = SEQ_editing_get(source_data.scene, false);
+ Editing *ed = SEQ_editing_get(source_data.scene);
if (ed == nullptr) {
return tree;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 16b690dd6e4..081f0241e94 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -185,7 +185,7 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type)
Sequence *tgt = NULL;
Sequence *seq;
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, true);
+ Editing *ed = SEQ_editing_ensure(scene);
int timeline_frame = (int)CFRA;
int proximity = INT_MAX;
@@ -314,7 +314,7 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm
static void seq_load_apply_generic_options(bContext *C, wmOperator *op, Sequence *seq)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (seq == NULL) {
return;
@@ -356,7 +356,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- const Editing *ed = SEQ_editing_get(scene, true);
+ const Editing *ed = SEQ_editing_ensure(scene);
Scene *sce_seq = BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene"));
if (sce_seq == NULL) {
@@ -384,7 +384,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
static void sequencer_disable_one_time_properties(bContext *C, wmOperator *op)
{
- Editing *ed = SEQ_editing_get(CTX_data_scene(C), false);
+ Editing *ed = SEQ_editing_get(CTX_data_scene(C));
/* Disable following properties if there are any existing strips, unless overridden by user. */
if (ed && ed->seqbasep && ed->seqbasep->first) {
if (RNA_struct_find_property(op->ptr, "use_framerate")) {
@@ -435,7 +435,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- const Editing *ed = SEQ_editing_get(scene, true);
+ const Editing *ed = SEQ_editing_ensure(scene);
MovieClip *clip = BLI_findlink(&bmain->movieclips, RNA_enum_get(op->ptr, "clip"));
if (clip == NULL) {
@@ -499,7 +499,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- const Editing *ed = SEQ_editing_get(scene, true);
+ const Editing *ed = SEQ_editing_ensure(scene);
Mask *mask = BLI_findlink(&bmain->masks, RNA_enum_get(op->ptr, "mask"));
if (mask == NULL) {
@@ -632,7 +632,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- const Editing *ed = SEQ_editing_get(scene, true);
+ const Editing *ed = SEQ_editing_ensure(scene);
RNA_BEGIN (op->ptr, itemptr, "files") {
char dir_only[FILE_MAX];
@@ -668,7 +668,7 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- const Editing *ed = SEQ_editing_get(scene, true);
+ const Editing *ed = SEQ_editing_ensure(scene);
Sequence *seq_movie = NULL;
Sequence *seq_sound = NULL;
@@ -817,7 +817,7 @@ static void sequencer_add_sound_multiple_strips(bContext *C,
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, true);
+ Editing *ed = SEQ_editing_ensure(scene);
RNA_BEGIN (op->ptr, itemptr, "files") {
char dir_only[FILE_MAX];
@@ -842,7 +842,7 @@ static bool sequencer_add_sound_single_strip(bContext *C, wmOperator *op, SeqLoa
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, true);
+ Editing *ed = SEQ_editing_ensure(scene);
Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, 0.0f);
if (seq == NULL) {
@@ -1035,7 +1035,7 @@ static void sequencer_add_image_strip_load_files(
static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, true);
+ Editing *ed = SEQ_editing_ensure(scene);
SeqLoadData load_data;
load_data_init_from_operator(&load_data, C, op);
@@ -1141,7 +1141,7 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, true);
+ Editing *ed = SEQ_editing_ensure(scene);
const char *error_msg;
SeqLoadData load_data;
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index fe3ff469e50..b56ad48cec2 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -2275,9 +2275,9 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
}
}
-static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
+static void seq_draw_sfra_efra(const Scene *scene, View2D *v2d)
{
- const Editing *ed = SEQ_editing_get(scene, false);
+ const Editing *ed = SEQ_editing_get(scene);
const int frame_sta = scene->r.sfra;
const int frame_end = scene->r.efra + 1;
@@ -2312,7 +2312,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
/* While in meta strip, draw a checkerboard overlay outside of frame range. */
if (ed && !BLI_listbase_is_empty(&ed->metastack)) {
- MetaStack *ms = ed->metastack.last;
+ const MetaStack *ms = ed->metastack.last;
immUnbindProgram();
immBindBuiltinProgram(GPU_SHADER_2D_CHECKER);
@@ -2586,7 +2586,7 @@ static void draw_overlap_frame_indicator(const struct Scene *scene, const View2D
void draw_timeline_seq(const bContext *C, ARegion *region)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
SpaceSeq *sseq = CTX_wm_space_seq(C);
View2D *v2d = &region->v2d;
short cfra_flag = 0;
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 935bc97d0b2..b95b7fa0620 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -190,14 +190,14 @@ bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
/* Operator functions. */
bool sequencer_edit_poll(bContext *C)
{
- return (SEQ_editing_get(CTX_data_scene(C), false) != NULL);
+ return (SEQ_editing_get(CTX_data_scene(C)) != NULL);
}
#if 0 /* UNUSED */
bool sequencer_strip_poll(bContext *C)
{
Editing *ed;
- return (((ed = SEQ_editing_get(CTX_data_scene(C), false)) != NULL) &&
+ return (((ed = SEQ_editing_get(CTX_data_scene(C))) != NULL) &&
(ed->act_seq != NULL));
}
#endif
@@ -206,14 +206,14 @@ bool sequencer_strip_has_path_poll(bContext *C)
{
Editing *ed;
Sequence *seq;
- return (((ed = SEQ_editing_get(CTX_data_scene(C), false)) != NULL) &&
- ((seq = ed->act_seq) != NULL) && (SEQ_HAS_PATH(seq)));
+ return (((ed = SEQ_editing_get(CTX_data_scene(C))) != NULL) && ((seq = ed->act_seq) != NULL) &&
+ (SEQ_HAS_PATH(seq)));
}
bool sequencer_view_preview_poll(bContext *C)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
- Editing *ed = SEQ_editing_get(CTX_data_scene(C), false);
+ Editing *ed = SEQ_editing_get(CTX_data_scene(C));
if (ed && sseq && (sseq->mainb == SEQ_DRAW_IMG_IMBUF)) {
return 1;
}
@@ -241,7 +241,7 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
const bool do_all = RNA_boolean_get(op->ptr, "all");
- const Editing *ed = SEQ_editing_get(scene, false);
+ const Editing *ed = SEQ_editing_get(scene);
SEQ_edit_remove_gaps(scene, ed->seqbasep, CFRA, do_all);
@@ -281,7 +281,7 @@ static int sequencer_gap_insert_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
const int frames = RNA_int_get(op->ptr, "frames");
- const Editing *ed = SEQ_editing_get(scene, false);
+ const Editing *ed = SEQ_editing_get(scene);
SEQ_transform_offset_after_frame(scene, ed->seqbasep, frames, CFRA);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -327,7 +327,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
int snap_frame;
@@ -531,7 +531,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
{
SlipData *data;
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
float mouseloc[2];
int num_seq;
View2D *v2d = UI_view2d_fromcontext(C);
@@ -579,7 +579,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
{
/* Only data types supported for now. */
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
bool changed = false;
/* Iterate in reverse so meta-strips are iterated after their children. */
@@ -663,7 +663,7 @@ static void sequencer_slip_apply_limits(SlipData *data, int *offset)
static int sequencer_slip_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
int offset = RNA_int_get(op->ptr, "offset");
bool success = false;
@@ -798,7 +798,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
case EVT_ESCKEY:
case RIGHTMOUSE: {
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
for (int i = 0; i < data->num_seq; i++) {
transseq_restore(data->ts + i, data->seq_array[i]);
@@ -900,7 +900,7 @@ void SEQUENCER_OT_slip(struct wmOperatorType *ot)
static int sequencer_mute_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
bool selected;
@@ -956,7 +956,7 @@ void SEQUENCER_OT_mute(struct wmOperatorType *ot)
static int sequencer_unmute_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
bool selected;
@@ -1012,7 +1012,7 @@ void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
static int sequencer_lock_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
@@ -1050,7 +1050,7 @@ void SEQUENCER_OT_lock(struct wmOperatorType *ot)
static int sequencer_unlock_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
@@ -1089,7 +1089,7 @@ static int sequencer_reload_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
const bool adjust_length = RNA_boolean_get(op->ptr, "adjust_length");
@@ -1152,7 +1152,7 @@ static bool sequencer_refresh_all_poll(bContext *C)
static int sequencer_refresh_all_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
SEQ_relations_free_imbuf(scene, &ed->seqbase, false);
@@ -1187,7 +1187,7 @@ int seq_effect_find_selected(Scene *scene,
Sequence **r_selseq3,
const char **r_error_str)
{
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq1 = NULL, *seq2 = NULL, *seq3 = NULL, *seq;
*r_error_str = NULL;
@@ -1316,7 +1316,7 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op)
static bool sequencer_effect_poll(bContext *C)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (ed) {
Sequence *last_seq = SEQ_select_active_get(scene);
@@ -1423,7 +1423,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
bool changed = false;
bool seq_selected = false;
@@ -1628,7 +1628,7 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot)
static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (ed == NULL) {
return OPERATOR_CANCELLED;
@@ -1688,7 +1688,7 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
SEQ_prefetch_stop(scene);
@@ -1747,7 +1747,7 @@ void SEQUENCER_OT_delete(wmOperatorType *ot)
static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
/* For effects, try to find a replacement input. */
@@ -1802,7 +1802,7 @@ void SEQUENCER_OT_offset_clear(wmOperatorType *ot)
static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq, *seq_new;
Strip *strip_new;
@@ -1908,7 +1908,7 @@ void SEQUENCER_OT_images_separate(wmOperatorType *ot)
static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *active_seq = SEQ_select_active_get(scene);
if (active_seq && active_seq->type == SEQ_TYPE_META && active_seq->flag & SELECT) {
@@ -1959,7 +1959,7 @@ void SEQUENCER_OT_meta_toggle(wmOperatorType *ot)
static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *active_seq = SEQ_select_active_get(scene);
ListBase *active_seqbase = SEQ_active_seqbase_get(ed);
@@ -2027,7 +2027,7 @@ void SEQUENCER_OT_meta_make(wmOperatorType *ot)
static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *active_seq = SEQ_select_active_get(scene);
if (active_seq == NULL || active_seq->type != SEQ_TYPE_META) {
@@ -2181,7 +2181,7 @@ static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, i
{
/* sel: 0==unselected, 1==selected, -1==don't care. */
Sequence *seq, *best_seq = NULL;
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
int dist, best_dist;
best_dist = MAXFRAME * 2;
@@ -2231,7 +2231,7 @@ static bool seq_is_parent(Sequence *par, Sequence *seq)
static int sequencer_swap_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *active_seq = SEQ_select_active_get(scene);
Sequence *seq, *iseq;
int side = RNA_enum_get(op->ptr, "side");
@@ -2399,7 +2399,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
SEQ_clipboard_free();
@@ -2456,7 +2456,7 @@ void SEQUENCER_OT_copy(wmOperatorType *ot)
void ED_sequencer_deselect_all(Scene *scene)
{
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (ed == NULL) {
return;
@@ -2471,7 +2471,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, true); /* Create if needed. */
+ Editing *ed = SEQ_editing_ensure(scene); /* Create if needed. */
ListBase nseqbase = {NULL, NULL};
int ofs;
Sequence *iseq, *iseq_first;
@@ -2640,7 +2640,7 @@ static const EnumPropertyItem prop_change_effect_input_types[] = {
static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq = SEQ_select_active_get(scene);
Sequence **seq_1, **seq_2;
@@ -2724,7 +2724,7 @@ EnumPropertyItem sequencer_prop_effect_types[] = {
static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq = SEQ_select_active_get(scene);
const int new_type = RNA_enum_get(op->ptr, "type");
@@ -2790,7 +2790,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq = SEQ_select_active_get(scene);
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
@@ -3000,7 +3000,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Sequence *seq, *seq_next;
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
ListBase text_seq = {0};
int iter = 0;
FILE *file;
@@ -3077,8 +3077,8 @@ static bool sequencer_strip_is_text_poll(bContext *C)
{
Editing *ed;
Sequence *seq;
- return (((ed = SEQ_editing_get(CTX_data_scene(C), false)) != NULL) &&
- ((seq = ed->act_seq) != NULL) && (seq->type == SEQ_TYPE_TEXT));
+ return (((ed = SEQ_editing_get(CTX_data_scene(C))) != NULL) && ((seq = ed->act_seq) != NULL) &&
+ (seq->type == SEQ_TYPE_TEXT));
}
void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot)
@@ -3114,7 +3114,7 @@ void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot)
static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
int sfra = MAXFRAME;
@@ -3199,7 +3199,7 @@ static const EnumPropertyItem transform_reset_properties[] = {
static int sequencer_strip_transform_clear_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- const Editing *ed = SEQ_editing_get(scene, false);
+ const Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
const int property = RNA_enum_get(op->ptr, "property");
@@ -3272,7 +3272,7 @@ static const EnumPropertyItem scale_fit_methods[] = {
static int sequencer_strip_transform_fit_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- const Editing *ed = SEQ_editing_get(scene, false);
+ const Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
const eSeqImageFitMethod fit_method = RNA_enum_get(op->ptr, "fit_method");
diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c
index 9b3ecacceb9..dd8595622f8 100644
--- a/source/blender/editors/space_sequencer/sequencer_modifier.c
+++ b/source/blender/editors/space_sequencer/sequencer_modifier.c
@@ -48,7 +48,7 @@
static bool strip_modifier_active_poll(bContext *C)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (ed) {
Sequence *seq = SEQ_select_active_get(scene);
diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c
index 16d14b5fa72..0a8eb7cb88f 100644
--- a/source/blender/editors/space_sequencer/sequencer_proxy.c
+++ b/source/blender/editors/space_sequencer/sequencer_proxy.c
@@ -56,7 +56,7 @@
static void seq_proxy_build_job(const bContext *C, ReportList *reports)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
ScrArea *area = CTX_wm_area(C);
if (ed == NULL) {
@@ -121,7 +121,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
Main *bmain = CTX_data_main(C);
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
GSet *file_list;
if (ed == NULL) {
@@ -184,7 +184,7 @@ static int sequencer_enable_proxies_invoke(bContext *C,
static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
bool proxy_25 = RNA_boolean_get(op->ptr, "proxy_25");
bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50");
bool proxy_75 = RNA_boolean_get(op->ptr, "proxy_75");
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 333edd0ed5f..80d3e2cbdaa 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -202,7 +202,7 @@ void select_surround_from_last(Scene *scene)
void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool deselect_all)
{
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (deselect_all) {
ED_sequencer_deselect_all(scene);
@@ -236,7 +236,7 @@ Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int se
{
/* sel: 0==unselected, 1==selected, -1==don't care. */
Sequence *seq;
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (ed == NULL) {
return NULL;
@@ -270,7 +270,7 @@ Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int se
Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[2])
{
Sequence *seq;
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
float x, y;
float pixelx;
float handsize;
@@ -396,7 +396,7 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
int action = RNA_enum_get(op->ptr, "action");
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
if (action == SEL_TOGGLE) {
@@ -463,7 +463,7 @@ void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
@@ -504,238 +504,245 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
/** \name Select Operator
* \{ */
-static int sequencer_select_exec(bContext *C, wmOperator *op)
+static void sequencer_select_set_active(Scene *scene, Sequence *seq)
{
- View2D *v2d = UI_view2d_fromcontext(C);
- Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
- const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle");
- const bool linked_time = RNA_boolean_get(op->ptr, "linked_time");
- bool side_of_frame = RNA_boolean_get(op->ptr, "side_of_frame");
- bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
- int mval[2];
- int ret_value = OPERATOR_CANCELLED;
+ Editing *ed = SEQ_editing_get(scene);
- mval[0] = RNA_int_get(op->ptr, "mouse_x");
- mval[1] = RNA_int_get(op->ptr, "mouse_y");
-
- Sequence *seq, *neighbor, *act_orig;
- int hand, sel_side;
+ SEQ_select_active_set(scene, seq);
- if (ed == NULL) {
- return OPERATOR_CANCELLED;
+ if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
+ if (seq->strip) {
+ BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
+ }
}
-
- if (extend) {
- wait_to_deselect_others = false;
+ else if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ if (seq->strip) {
+ BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
+ }
}
+ recurs_sel_seq(seq);
+}
- seq = find_nearest_seq(scene, v2d, &hand, mval);
-
- /* XXX: not nice, Ctrl+RMB needs to do side_of_frame only when not over a strip. */
- if (seq && linked_time) {
- side_of_frame = false;
- }
+static void sequencer_select_do_updates(bContext *C, Scene *scene)
+{
+ ED_outliner_select_sync_from_sequence_tag(C);
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
+}
- /* Select left, right or overlapping the current frame. */
- if (side_of_frame) {
- /* Use different logic for this. */
- if (extend == false) {
- ED_sequencer_deselect_all(scene);
+static void sequencer_select_side_of_frame(const bContext *C,
+ const View2D *v2d,
+ const int mval[2],
+ Scene *scene)
+{
+ Editing *ed = SEQ_editing_get(scene);
+
+ const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
+ LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
+ if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) ||
+ ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) {
+ /* Select left or right. */
+ seq_iter->flag |= SELECT;
+ recurs_sel_seq(seq_iter);
}
+ }
- const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
+ {
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
+ TimeMarker *tmarker;
- LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
- if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) ||
- ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) {
- /* Select left or right. */
- seq_iter->flag |= SELECT;
- recurs_sel_seq(seq_iter);
+ for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
+ if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
+ ((x >= CFRA) && (tmarker->frame >= CFRA))) {
+ tmarker->flag |= SELECT;
+ }
+ else {
+ tmarker->flag &= ~SELECT;
+ }
}
}
+ }
+}
- {
- SpaceSeq *sseq = CTX_wm_space_seq(C);
- if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
- TimeMarker *tmarker;
+static void sequencer_select_linked_handle(const bContext *C,
+ Sequence *seq,
+ const int handle_clicked)
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ if (!ELEM(handle_clicked, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
+ /* First click selects the strip and its adjacent handles (if valid).
+ * Second click selects the strip,
+ * both of its handles and its adjacent handles (if valid). */
+ const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
+ seq->flag &= ~SEQ_ALLSEL;
+ seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
+ select_surrounding_handles(scene, seq);
+ }
+ else {
+ /* Always select the strip under the cursor. */
+ seq->flag |= SELECT;
- for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
- if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
- ((x >= CFRA) && (tmarker->frame >= CFRA))) {
- tmarker->flag |= SELECT;
+ /* First click selects adjacent handles on that side.
+ * Second click selects all strips in that direction.
+ * If there are no adjacent strips, it just selects all in that direction.
+ */
+ int sel_side = handle_clicked;
+ Sequence *neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
+ if (neighbor) {
+ switch (sel_side) {
+ case SEQ_SIDE_LEFT:
+ if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
+ seq->flag |= SELECT;
+ select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
}
else {
- tmarker->flag &= ~SELECT;
+ seq->flag |= SELECT;
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_RIGHTSEL;
+ seq->flag |= SEQ_LEFTSEL;
}
- }
+ break;
+ case SEQ_SIDE_RIGHT:
+ if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
+ seq->flag |= SELECT;
+ select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
+ }
+ else {
+ seq->flag |= SELECT;
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_LEFTSEL;
+ seq->flag |= SEQ_RIGHTSEL;
+ }
+ break;
}
}
+ else {
- ret_value = OPERATOR_FINISHED;
+ select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
+ }
}
- else {
- act_orig = ed->act_seq;
-
- if (seq) {
- /* Are we trying to select a handle that's already selected? */
- const bool handle_selected = ((hand == SEQ_SIDE_LEFT) && (seq->flag & SEQ_LEFTSEL)) ||
- ((hand == SEQ_SIDE_RIGHT) && (seq->flag & SEQ_RIGHTSEL));
-
- if (wait_to_deselect_others && (seq->flag & SELECT) &&
- (hand == SEQ_SIDE_NONE || handle_selected)) {
- ret_value = OPERATOR_RUNNING_MODAL;
- }
- else if (!extend && !linked_handle) {
- ED_sequencer_deselect_all(scene);
- ret_value = OPERATOR_FINISHED;
- }
- else {
- ret_value = OPERATOR_FINISHED;
- }
-
- SEQ_select_active_set(scene, seq);
+}
- if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
- if (seq->strip) {
- BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
- }
- }
- else if (seq->type == SEQ_TYPE_SOUND_RAM) {
- if (seq->strip) {
- BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
- }
- }
+static bool element_already_selected(const Sequence *seq, const int handle_clicked)
+{
+ const bool handle_already_selected = ((handle_clicked == SEQ_SIDE_LEFT) &&
+ (seq->flag & SEQ_LEFTSEL)) ||
+ ((handle_clicked == SEQ_SIDE_RIGHT) &&
+ (seq->flag & SEQ_RIGHTSEL));
+ return ((seq->flag & SELECT) && handle_clicked == SEQ_SIDE_NONE) || handle_already_selected;
+}
- /* On Alt selection, select the strip and bordering handles. */
- if (linked_handle) {
- if (!ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
- /* First click selects the strip and its adjacent handles (if valid).
- * Second click selects the strip,
- * both of its handles and its adjacent handles (if valid). */
- const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
+static void sequencer_select_strip_impl(const Editing *ed,
+ Sequence *seq,
+ const int handle_clicked,
+ const bool extend)
+{
+ /* Deselect strip. */
+ if (extend && (seq->flag & SELECT) && ed->act_seq == seq) {
+ switch (handle_clicked) {
+ case SEQ_SIDE_NONE:
+ seq->flag &= ~SEQ_ALLSEL;
+ break;
+ case SEQ_SIDE_LEFT:
+ seq->flag ^= SEQ_LEFTSEL;
+ break;
+ case SEQ_SIDE_RIGHT:
+ seq->flag ^= SEQ_RIGHTSEL;
+ break;
+ }
+ }
+ else { /* Select strip. */
+ seq->flag |= SELECT;
+ if (handle_clicked == SEQ_SIDE_LEFT) {
+ seq->flag |= SEQ_LEFTSEL;
+ }
+ if (handle_clicked == SEQ_SIDE_RIGHT) {
+ seq->flag |= SEQ_RIGHTSEL;
+ }
+ }
+}
- if (!extend) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag &= ~SEQ_ALLSEL;
- seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
- select_surrounding_handles(scene, seq);
- }
- else {
- /* Always select the strip under the cursor. */
- seq->flag |= SELECT;
+static int sequencer_select_exec(bContext *C, wmOperator *op)
+{
+ View2D *v2d = UI_view2d_fromcontext(C);
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
- /* First click selects adjacent handles on that side.
- * Second click selects all strips in that direction.
- * If there are no adjacent strips, it just selects all in that direction.
- */
- sel_side = hand;
- neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
- if (neighbor) {
- switch (sel_side) {
- case SEQ_SIDE_LEFT:
- if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
- }
- else {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- neighbor->flag |= SELECT;
- recurs_sel_seq(neighbor);
- neighbor->flag |= SEQ_RIGHTSEL;
- seq->flag |= SEQ_LEFTSEL;
- }
- break;
- case SEQ_SIDE_RIGHT:
- if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
- }
- else {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- neighbor->flag |= SELECT;
- recurs_sel_seq(neighbor);
- neighbor->flag |= SEQ_LEFTSEL;
- seq->flag |= SEQ_RIGHTSEL;
- }
- break;
- }
- }
- else {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
- }
- }
+ if (ed == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- ret_value = OPERATOR_FINISHED;
- }
- else {
- if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
- switch (hand) {
- case SEQ_SIDE_NONE:
- if (linked_handle == 0) {
- seq->flag &= ~SEQ_ALLSEL;
- }
- break;
- case SEQ_SIDE_LEFT:
- seq->flag ^= SEQ_LEFTSEL;
- break;
- case SEQ_SIDE_RIGHT:
- seq->flag ^= SEQ_RIGHTSEL;
- break;
- }
- ret_value = OPERATOR_FINISHED;
- }
- else {
- seq->flag |= SELECT;
- if (hand == SEQ_SIDE_LEFT) {
- seq->flag |= SEQ_LEFTSEL;
- }
- if (hand == SEQ_SIDE_RIGHT) {
- seq->flag |= SEQ_RIGHTSEL;
- }
- }
- }
+ int mval[2];
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
- recurs_sel_seq(seq);
+ int handle_clicked;
+ Sequence *seq = find_nearest_seq(scene, v2d, &handle_clicked, mval);
- if (linked_time) {
- select_linked_time(ed->seqbasep, seq);
- }
+ /* NOTE: `side_of_frame` and `linked_time` functionality is designed to be shared on one keymap,
+ * therefore both properties can be true at the same time. */
+ if (seq && RNA_boolean_get(op->ptr, "linked_time")) {
+ if (!extend) {
+ ED_sequencer_deselect_all(scene);
+ }
+ sequencer_select_strip_impl(ed, seq, handle_clicked, extend);
+ select_linked_time(ed->seqbasep, seq);
+ sequencer_select_do_updates(C, scene);
+ sequencer_select_set_active(scene, seq);
+ return OPERATOR_FINISHED;
+ }
- BLI_assert((ret_value & OPERATOR_CANCELLED) == 0);
+ /* Select left, right or overlapping the current frame. */
+ if (RNA_boolean_get(op->ptr, "side_of_frame")) {
+ if (!extend) {
+ ED_sequencer_deselect_all(scene);
}
- else if (deselect_all) {
+ sequencer_select_side_of_frame(C, v2d, mval, scene);
+ sequencer_select_do_updates(C, scene);
+ return OPERATOR_FINISHED;
+ }
+
+ /* On Alt selection, select the strip and bordering handles. */
+ if (seq && RNA_boolean_get(op->ptr, "linked_handle")) {
+ if (!extend) {
ED_sequencer_deselect_all(scene);
- ret_value = OPERATOR_FINISHED;
}
+ sequencer_select_linked_handle(C, seq, handle_clicked);
+ sequencer_select_do_updates(C, scene);
+ sequencer_select_set_active(scene, seq);
+ return OPERATOR_FINISHED;
}
- ED_outliner_select_sync_from_sequence_tag(C);
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
+ /* Clicking on already selected element falls on modal operation.
+ * All strips are deselected on mouse button release unless extend mode is used. */
+ if (seq && element_already_selected(seq, handle_clicked) && wait_to_deselect_others && !extend) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ int ret_value = OPERATOR_CANCELLED;
+
+ if (!extend) {
+ ED_sequencer_deselect_all(scene);
+ ret_value = OPERATOR_FINISHED;
+ }
+
+ /* Nothing to select, but strips could be deselected. */
+ if (!seq) {
+ sequencer_select_do_updates(C, scene);
+ return ret_value;
+ }
+ /* Do actual selection. */
+ sequencer_select_strip_impl(ed, seq, handle_clicked, extend);
+ ret_value = OPERATOR_FINISHED;
+ sequencer_select_do_updates(C, scene);
+ sequencer_select_set_active(scene, seq);
return ret_value;
}
@@ -764,13 +771,6 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
- "deselect_all",
- false,
- "Deselect On Nothing",
- "Deselect all when nothing under the cursor");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_boolean(ot->srna,
"linked_handle",
false,
"Linked Handle",
@@ -799,7 +799,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
/* Run recursively to select linked. */
static bool select_linked_internal(Scene *scene)
{
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (ed == NULL) {
return false;
@@ -832,7 +832,7 @@ static bool select_linked_internal(Scene *scene)
/* Select only one linked strip on each side. */
static bool select_more_less_seq__internal(Scene *scene, bool select_more)
{
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (ed == NULL) {
return false;
@@ -1070,7 +1070,7 @@ static const EnumPropertyItem prop_select_handles_side_types[] = {
static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
int sel_side = RNA_enum_get(op->ptr, "side");
@@ -1169,7 +1169,7 @@ void SEQUENCER_OT_select_handles(wmOperatorType *ot)
static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
const bool extend = RNA_boolean_get(op->ptr, "extend");
const int side = RNA_enum_get(op->ptr, "side");
@@ -1244,7 +1244,7 @@ void SEQUENCER_OT_select_side_of_frame(wmOperatorType *ot)
static int sequencer_select_side_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
const int sel_side = RNA_enum_get(op->ptr, "side");
const int frame_init = sel_side == SEQ_SIDE_LEFT ? INT_MIN : INT_MAX;
@@ -1315,7 +1315,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
View2D *v2d = UI_view2d_fromcontext(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
if (ed == NULL) {
return OPERATOR_CANCELLED;
@@ -1679,7 +1679,7 @@ static bool select_grouped_effect_link(Editing *ed,
static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *actseq = SEQ_select_active_get(scene);
if (actseq == NULL) {
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index a0a9cdd96b1..981f793c896 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -90,7 +90,7 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op)
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
Scene *scene = CTX_data_scene(C);
- const Editing *ed = SEQ_editing_get(scene, false);
+ const Editing *ed = SEQ_editing_get(scene);
SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &box);
UI_view2d_smooth_view(C, region, &box, smooth_viewtx);
@@ -274,7 +274,7 @@ static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
View2D *v2d = UI_view2d_fromcontext(C);
ARegion *region = CTX_wm_region(C);
- Editing *ed = SEQ_editing_get(scene, false);
+ Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
rctf cur_new = v2d->cur;
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index fcc92345bea..a82648aeee0 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -270,7 +270,7 @@ Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet,
return nullptr;
}
Object *object_orig = (Object *)used_id;
- if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD, OB_VOLUME)) {
+ if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD, OB_VOLUME, OB_CURVE, OB_FONT)) {
return nullptr;
}
@@ -370,7 +370,7 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
std::unique_ptr<ColumnValues> values_ptr = data_source->get_column_values(*column->id);
/* Should have been removed before if it does not exist anymore. */
BLI_assert(values_ptr);
- const ColumnValues *values = scope.add(std::move(values_ptr), __func__);
+ const ColumnValues *values = scope.add(std::move(values_ptr));
const int width = get_column_width_in_pixels(*values);
spreadsheet_layout.columns.append({values, width});
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
index 680da9b6794..97170693cb3 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
@@ -35,6 +35,10 @@ struct CollectionCellValue {
const Collection *collection;
};
+struct GeometrySetCellValue {
+ const GeometrySet *geometry_set;
+};
+
/**
* This is a type that can hold the value of a cell in a spreadsheet. This type allows us to
* decouple the drawing of individual cells from the code that generates the data to be displayed.
@@ -53,6 +57,7 @@ class CellValue {
std::optional<ColorGeometry4f> value_color;
std::optional<ObjectCellValue> value_object;
std::optional<CollectionCellValue> value_collection;
+ std::optional<GeometrySetCellValue> value_geometry_set;
};
} // namespace blender::ed::spreadsheet
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 e38c70afd0f..78d9f61d8d5 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -45,15 +45,19 @@ namespace blender::ed::spreadsheet {
void GeometryDataSource::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &)> fn) const
{
- component_->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
- if (meta_data.domain != domain_) {
- return true;
- }
- SpreadsheetColumnID column_id;
- column_id.name = (char *)name.c_str();
- fn(column_id);
- return true;
- });
+ component_->attribute_foreach(
+ [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ if (meta_data.domain != domain_) {
+ return true;
+ }
+ if (attribute_id.is_anonymous()) {
+ return true;
+ }
+ SpreadsheetColumnID column_id;
+ column_id.name = (char *)attribute_id.name().data();
+ fn(column_id);
+ return true;
+ });
}
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
@@ -65,7 +69,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
if (!attribute) {
return {};
}
- const fn::GVArray *varray = scope_.add(std::move(attribute.varray), __func__);
+ const fn::GVArray *varray = scope_.add(std::move(attribute.varray));
if (attribute.domain != domain_) {
return {};
}
@@ -332,6 +336,11 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
r_cell_value.value_collection = CollectionCellValue{&collection};
break;
}
+ case InstanceReference::Type::GeometrySet: {
+ const GeometrySet &geometry_set = reference.geometry_set();
+ r_cell_value.value_geometry_set = GeometrySetCellValue{&geometry_set};
+ break;
+ }
case InstanceReference::Type::None: {
break;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index 8079763a339..1a5eac53306 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -209,6 +209,23 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
0,
nullptr);
}
+ else if (cell_value.value_geometry_set.has_value()) {
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_MESH_DATA,
+ "Geometry",
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ }
}
void draw_float_vector(const CellDrawParams &params, const Span<float> values) const
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index ae336edfead..1e46fef8d71 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -328,7 +328,7 @@ Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
geometry_data_source->apply_selection_filter(rows_included);
}
- Vector<int64_t> &indices = scope.construct<Vector<int64_t>>(__func__);
+ Vector<int64_t> &indices = scope.construct<Vector<int64_t>>();
index_vector_from_bools(rows_included, indices);
return indices;
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 466820353b9..8ed134c7fd1 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -3961,9 +3961,10 @@ static int view_axis_exec(bContext *C, wmOperator *op)
Object *obact = CTX_data_active_object(C);
if (obact != NULL) {
float twmat[3][3];
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obedit = CTX_data_edit_object(C);
/* same as transform gizmo when normal is set */
- ED_getTransformOrientationMatrix(C, obact, obedit, V3D_AROUND_ACTIVE, twmat);
+ ED_getTransformOrientationMatrix(view_layer, v3d, obact, obedit, V3D_AROUND_ACTIVE, twmat);
align_quat = align_quat_buf;
mat3_to_quat(align_quat, twmat);
invert_qt_normalized(align_quat);
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index edc34d0d883..f8278edbcae 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -33,6 +33,7 @@
#include "BKE_material.h"
#include "BKE_object.h"
+#include "BKE_scene.h"
#include "BKE_unit.h"
#include "DNA_gpencil_types.h"
@@ -44,6 +45,7 @@
#include "ED_gizmo_utils.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
+#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "ED_view3d.h"
@@ -69,6 +71,12 @@
#include "BLF_api.h"
+/**
+ * Supporting transform features could be removed if the actual transform system is used.
+ * Keep the option open since each transform feature is duplicating logic.
+ */
+#define USE_AXIS_CONSTRAINTS
+
static const char *view3d_gzgt_ruler_id = "VIEW3D_GGT_ruler";
#define MVAL_MAX_PX_DIST 12.0f
@@ -98,6 +106,24 @@ enum {
RULER_STATE_DRAG,
};
+#ifdef USE_AXIS_CONSTRAINTS
+/* Constrain axes */
+enum {
+ CONSTRAIN_AXIS_NONE = -1,
+ CONSTRAIN_AXIS_X = 0,
+ CONSTRAIN_AXIS_Y = 1,
+ CONSTRAIN_AXIS_Z = 2,
+};
+
+/* Constraining modes.
+ Off / Scene orientation / Global (or Local if Scene orientation is Global) */
+enum {
+ CONSTRAIN_MODE_OFF = 0,
+ CONSTRAIN_MODE_1 = 1,
+ CONSTRAIN_MODE_2 = 2,
+};
+#endif /* USE_AXIS_CONSTRAINTS */
+
struct RulerItem;
typedef struct RulerInfo {
@@ -106,6 +132,10 @@ typedef struct RulerInfo {
int snap_flag;
int state;
+#ifdef USE_AXIS_CONSTRAINTS
+ short constrain_axis, constrain_mode;
+#endif
+
/* wm state */
wmWindowManager *wm;
wmWindow *win;
@@ -394,6 +424,44 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
if (ED_gizmotypes_snap_3d_is_enabled(snap_gizmo)) {
ED_gizmotypes_snap_3d_data_get(snap_gizmo, co, NULL, NULL, NULL);
}
+
+#ifdef USE_AXIS_CONSTRAINTS
+ if (!(ruler_item->flag & RULERITEM_USE_ANGLE) &&
+ ruler_info->constrain_mode != CONSTRAIN_MODE_OFF) {
+
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ RegionView3D *rv3d = ruler_info->region->regiondata;
+ Object *ob = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_OBACT(ob);
+
+ short orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
+
+ if (ruler_info->constrain_mode == CONSTRAIN_MODE_2) {
+ orient_index = (orient_index == V3D_ORIENT_GLOBAL) ? V3D_ORIENT_LOCAL :
+ V3D_ORIENT_GLOBAL;
+ }
+
+ const int pivot_point = scene->toolsettings->transform_pivot_point;
+ float mat[3][3];
+
+ ED_transform_calc_orientation_from_type_ex(
+ scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, mat);
+
+ invert_m3(mat);
+ mul_m3_m3_pre(ruler_item->co, mat);
+
+ /* Loop through the axes and constrain the dragged point to the current constrained axis.
+ */
+ for (int i = 0; i <= 2; i++) {
+ if (ruler_info->constrain_axis != i) {
+ ruler_item->co[inter->co_index][i] = ruler_item->co[(inter->co_index == 0) ? 2 : 0][i];
+ }
+ }
+ invert_m3(mat);
+ mul_m3_m3_pre(ruler_item->co, mat);
+ }
+#endif
}
return true;
}
@@ -940,6 +1008,35 @@ static int gizmo_ruler_modal(bContext *C,
ruler_info->region = region;
+#ifdef USE_AXIS_CONSTRAINTS
+ if ((event->val == KM_PRESS) && ELEM(event->type, EVT_XKEY, EVT_YKEY, EVT_ZKEY)) {
+ /* Go to Mode 1 if a new axis is selected. */
+ if (event->type == EVT_XKEY && ruler_info->constrain_axis != CONSTRAIN_AXIS_X) {
+ ruler_info->constrain_axis = CONSTRAIN_AXIS_X;
+ ruler_info->constrain_mode = CONSTRAIN_MODE_1;
+ }
+ else if (event->type == EVT_YKEY && ruler_info->constrain_axis != CONSTRAIN_AXIS_Y) {
+ ruler_info->constrain_axis = CONSTRAIN_AXIS_Y;
+ ruler_info->constrain_mode = CONSTRAIN_MODE_1;
+ }
+ else if (event->type == EVT_ZKEY && ruler_info->constrain_axis != CONSTRAIN_AXIS_Z) {
+ ruler_info->constrain_axis = CONSTRAIN_AXIS_Z;
+ ruler_info->constrain_mode = CONSTRAIN_MODE_1;
+ }
+ else {
+ /* Cycle to the next mode if the same key is pressed again. */
+ if (ruler_info->constrain_mode != CONSTRAIN_MODE_2) {
+ ruler_info->constrain_mode++;
+ }
+ else {
+ ruler_info->constrain_mode = CONSTRAIN_MODE_OFF;
+ ruler_info->constrain_axis = CONSTRAIN_AXIS_NONE;
+ }
+ }
+ do_cursor_update = true;
+ }
+#endif
+
#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
const bool do_snap = !(tweak_flag & WM_GIZMO_TWEAK_SNAP);
#endif
@@ -986,6 +1083,11 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
const float mval_fl[2] = {UNPACK2(event->mval)};
+#ifdef USE_AXIS_CONSTRAINTS
+ ruler_info->constrain_axis = CONSTRAIN_AXIS_NONE;
+ ruler_info->constrain_mode = CONSTRAIN_MODE_OFF;
+#endif
+
/* select and drag */
if (gz->highlight_part == PART_LINE) {
if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) {
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index e3f97dd1c63..3f572bf9d5a 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1438,7 +1438,7 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);
@@ -1953,7 +1953,8 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc,
const int mval[2],
eV3DSelectObjectFilter select_filter,
bool do_nearest,
- bool do_nearest_xray_if_supported)
+ bool do_nearest_xray_if_supported,
+ const bool do_material_slot_selection)
{
rcti rect;
int hits15, hits9 = 0, hits5 = 0;
@@ -1972,7 +1973,8 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc,
view3d_opengl_select_cache_begin();
BLI_rcti_init_pt_radius(&rect, mval, 14);
- hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter);
+ hits15 = view3d_opengl_select_ex(
+ vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter, do_material_slot_selection);
if (hits15 == 1) {
hits = selectbuffer_ret_hits_15(buffer, hits15);
goto finally;
@@ -2071,7 +2073,8 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
do_nearest = do_nearest && !enumerate;
- int hits = mixed_bones_object_selectbuffer(vc, buffer, mval, select_filter, do_nearest, true);
+ int hits = mixed_bones_object_selectbuffer(
+ vc, buffer, mval, select_filter, do_nearest, true, false);
return hits;
}
@@ -2088,12 +2091,14 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
int hits,
Base *startbase,
bool has_bones,
- bool do_nearest)
+ bool do_nearest,
+ int *r_sub_selection)
{
ViewLayer *view_layer = vc->view_layer;
View3D *v3d = vc->v3d;
Base *base, *basact = NULL;
int a;
+ int sub_selection_id = 0;
if (do_nearest) {
uint min = 0xFFFFFFFF;
@@ -2105,6 +2110,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
if (min > buffer[4 * a + 1] && (buffer[4 * a + 3] & 0xFFFF0000)) {
min = buffer[4 * a + 1];
selcol = buffer[4 * a + 3] & 0xFFFF;
+ sub_selection_id = (buffer[4 * a + 3] & 0xFFFF0000) >> 16;
}
}
}
@@ -2118,6 +2124,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) {
min = buffer[4 * a + 1];
selcol = buffer[4 * a + 3] & 0xFFFF;
+ sub_selection_id = (buffer[4 * a + 3] & 0xFFFF0000) >> 16;
}
}
}
@@ -2184,11 +2191,16 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
}
}
+ if (basact && r_sub_selection) {
+ *r_sub_selection = sub_selection_id;
+ }
+
return basact;
}
-/* mval comes from event->mval, only use within region handlers */
-Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
+static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
+ const int mval[2],
+ int *r_material_slot)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
@@ -2202,18 +2214,30 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
ED_view3d_viewcontext_init(C, &vc, depsgraph);
const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
+ const bool do_material_slot_selection = r_material_slot != NULL;
const int hits = mixed_bones_object_selectbuffer(
- &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false);
+ &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false, do_material_slot_selection);
if (hits > 0) {
- const bool has_bones = selectbuffer_has_bones(buffer, hits);
- basact = mouse_select_eval_buffer(
- &vc, buffer, hits, vc.view_layer->object_bases.first, has_bones, do_nearest);
+ const bool has_bones = (r_material_slot == NULL) && selectbuffer_has_bones(buffer, hits);
+ basact = mouse_select_eval_buffer(&vc,
+ buffer,
+ hits,
+ vc.view_layer->object_bases.first,
+ has_bones,
+ do_nearest,
+ r_material_slot);
}
return basact;
}
+/* mval comes from event->mval, only use within region handlers */
+Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
+{
+ return ed_view3d_give_base_under_cursor_ex(C, mval, NULL);
+}
+
Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2])
{
Base *base = ED_view3d_give_base_under_cursor(C, mval);
@@ -2223,6 +2247,17 @@ Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2])
return NULL;
}
+struct Object *ED_view3d_give_material_slot_under_cursor(struct bContext *C,
+ const int mval[2],
+ int *r_material_slot)
+{
+ Base *base = ed_view3d_give_base_under_cursor_ex(C, mval, r_material_slot);
+ if (base) {
+ return base->object;
+ }
+ return NULL;
+}
+
bool ED_view3d_is_object_under_cursor(bContext *C, const int mval[2])
{
return ED_view3d_give_object_under_cursor(C, mval) != NULL;
@@ -2374,7 +2409,8 @@ static bool ed_object_select_pick(bContext *C,
}
}
else {
- basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest);
+ basact = mouse_select_eval_buffer(
+ &vc, buffer, hits, startbase, has_bones, do_nearest, NULL);
}
if (has_bones && basact) {
@@ -2436,7 +2472,7 @@ static bool ed_object_select_pick(bContext *C,
if (!changed) {
/* fallback to regular object selection if no new bundles were selected,
* allows to select object parented to reconstruction object */
- basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest);
+ basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest, NULL);
}
}
}
@@ -2677,7 +2713,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
uint buffer[MAXPICKBUF];
const int hits = mixed_bones_object_selectbuffer(
- &vc, buffer, location, VIEW3D_SELECT_FILTER_NOP, false, true);
+ &vc, buffer, location, VIEW3D_SELECT_FILTER_NOP, false, true, false);
retval = bone_mouse_select_menu(C, buffer, hits, true, extend, deselect, toggle);
}
if (!retval) {
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 86a610f8dd9..f5da7c14a88 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -137,7 +137,6 @@ void ED_view3d_smooth_view_ex(
{
RegionView3D *rv3d = region->regiondata;
struct SmoothView3DStore sms = {{0}};
- bool ok = false;
/* initialize sms */
view3d_smooth_view_state_backup(&sms.dst, v3d, rv3d);
@@ -200,92 +199,75 @@ void ED_view3d_smooth_view_ex(
sms.to_camera = true; /* restore view3d values in end */
}
- /* skip smooth viewing for external render engine draw */
+ if ((sview->camera_old == sview->camera) && /* Camera. */
+ (sms.dst.dist == rv3d->dist) && /* Distance. */
+ (sms.dst.lens == v3d->lens) && /* Lens. */
+ equals_v3v3(sms.dst.ofs, rv3d->ofs) && /* Offset. */
+ equals_v4v4(sms.dst.quat, rv3d->viewquat) /* Rotation. */
+ ) {
+ /* Early return if nothing changed. */
+ return;
+ }
+
+ /* Skip smooth viewing for external render engine draw. */
if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) {
- bool changed = false; /* zero means no difference */
- if (sview->camera_old != sview->camera) {
- changed = true;
- }
- else if (sms.dst.dist != rv3d->dist) {
- changed = true;
- }
- else if (sms.dst.lens != v3d->lens) {
- changed = true;
- }
- else if (!equals_v3v3(sms.dst.ofs, rv3d->ofs)) {
- changed = true;
+ /* original values */
+ if (sview->camera_old) {
+ Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old);
+ if (sview->ofs != NULL) {
+ sms.src.dist = ED_view3d_offset_distance(ob_camera_old_eval->obmat, sview->ofs, 0.0f);
+ }
+ ED_view3d_from_object(
+ ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens);
}
- else if (!equals_v4v4(sms.dst.quat, rv3d->viewquat)) {
- changed = true;
+ /* grid draw as floor */
+ if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
+ /* use existing if exists, means multiple calls to smooth view
+ * won't lose the original 'view' setting */
+ rv3d->view = RV3D_VIEW_USER;
}
- /* The new view is different from the old one
- * so animate the view */
- if (changed) {
- /* original values */
- if (sview->camera_old) {
- Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old);
- if (sview->ofs != NULL) {
- sms.src.dist = ED_view3d_offset_distance(ob_camera_old_eval->obmat, sview->ofs, 0.0f);
- }
- ED_view3d_from_object(
- ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens);
- }
- /* grid draw as floor */
- if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
- /* use existing if exists, means multiple calls to smooth view
- * won't lose the original 'view' setting */
- rv3d->view = RV3D_VIEW_USER;
- }
-
- sms.time_allowed = (double)smooth_viewtx / 1000.0;
-
- /* if this is view rotation only
- * we can decrease the time allowed by
- * the angle between quats
- * this means small rotations won't lag */
- if (sview->quat && !sview->ofs && !sview->dist) {
- /* scale the time allowed by the rotation */
- /* 180deg == 1.0 */
- sms.time_allowed *= (double)fabsf(
- angle_signed_normalized_qtqt(sms.dst.quat, sms.src.quat)) /
- M_PI;
- }
+ sms.time_allowed = (double)smooth_viewtx / 1000.0;
- /* ensure it shows correct */
- if (sms.to_camera) {
- /* use ortho if we move from an ortho view to an ortho camera */
- Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera);
- rv3d->persp = (((rv3d->is_persp == false) && (ob_camera_eval->type == OB_CAMERA) &&
- (((Camera *)ob_camera_eval->data)->type == CAM_ORTHO)) ?
- RV3D_ORTHO :
- RV3D_PERSP);
- }
+ /* If this is view rotation only we can decrease the time allowed by the angle between quats
+ * this means small rotations won't lag. */
+ if (sview->quat && !sview->ofs && !sview->dist) {
+ /* scale the time allowed by the rotation */
+ /* 180deg == 1.0 */
+ sms.time_allowed *= (double)fabsf(angle_signed_normalized_qtqt(sms.dst.quat, sms.src.quat)) /
+ M_PI;
+ }
- rv3d->rflag |= RV3D_NAVIGATING;
+ /* ensure it shows correct */
+ if (sms.to_camera) {
+ /* use ortho if we move from an ortho view to an ortho camera */
+ Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera);
+ rv3d->persp = (((rv3d->is_persp == false) && (ob_camera_eval->type == OB_CAMERA) &&
+ (((Camera *)ob_camera_eval->data)->type == CAM_ORTHO)) ?
+ RV3D_ORTHO :
+ RV3D_PERSP);
+ }
- /* not essential but in some cases the caller will tag the area for redraw, and in that
- * case we can get a flicker of the 'org' user view but we want to see 'src' */
- view3d_smooth_view_state_restore(&sms.src, v3d, rv3d);
+ rv3d->rflag |= RV3D_NAVIGATING;
- /* keep track of running timer! */
- if (rv3d->sms == NULL) {
- rv3d->sms = MEM_mallocN(sizeof(struct SmoothView3DStore), "smoothview v3d");
- }
- *rv3d->sms = sms;
- if (rv3d->smooth_timer) {
- WM_event_remove_timer(wm, win, rv3d->smooth_timer);
- }
- /* #TIMER1 is hard-coded in key-map. */
- rv3d->smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0);
+ /* not essential but in some cases the caller will tag the area for redraw, and in that
+ * case we can get a flicker of the 'org' user view but we want to see 'src' */
+ view3d_smooth_view_state_restore(&sms.src, v3d, rv3d);
- ok = true;
+ /* keep track of running timer! */
+ if (rv3d->sms == NULL) {
+ rv3d->sms = MEM_mallocN(sizeof(struct SmoothView3DStore), "smoothview v3d");
+ }
+ *rv3d->sms = sms;
+ if (rv3d->smooth_timer) {
+ WM_event_remove_timer(wm, win, rv3d->smooth_timer);
}
+ /* #TIMER1 is hard-coded in key-map. */
+ rv3d->smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0);
}
-
- /* if we get here nothing happens */
- if (ok == false) {
+ else {
+ /* Animation is disabled, apply immediately. */
if (sms.to_camera == false) {
copy_v3_v3(rv3d->ofs, sms.dst.ofs);
copy_qt_qt(rv3d->viewquat, sms.dst.quat);
@@ -300,6 +282,8 @@ void ED_view3d_smooth_view_ex(
}
ED_region_tag_redraw(region);
+
+ WM_event_add_mousemove(win);
}
}
@@ -320,6 +304,7 @@ void ED_view3d_smooth_view(bContext *C,
/* only meant for timer usage */
static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, bool sync_boxview)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
RegionView3D *rv3d = region->regiondata;
struct SmoothView3DStore *sms = rv3d->sms;
float step, step_inv;
@@ -333,6 +318,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
/* end timer */
if (step >= 1.0f) {
+ wmWindow *win = CTX_wm_window(C);
/* if we went to camera, store the original */
if (sms->to_camera) {
@@ -355,9 +341,12 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
MEM_freeN(rv3d->sms);
rv3d->sms = NULL;
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
+ WM_event_remove_timer(wm, win, rv3d->smooth_timer);
rv3d->smooth_timer = NULL;
rv3d->rflag &= ~RV3D_NAVIGATING;
+
+ /* Event handling won't know if a UI item has been moved under the pointer. */
+ WM_event_add_mousemove(win);
}
else {
/* ease in/out */
@@ -380,12 +369,9 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
- if (ED_screen_animation_playing(CTX_wm_manager(C))) {
+ if (ED_screen_animation_playing(wm)) {
ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
}
-
- /* Event handling won't know if a UI item has been moved under the pointer. */
- WM_event_add_mousemove(CTX_wm_window(C));
}
if (sync_boxview && (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW)) {
@@ -964,12 +950,13 @@ static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void
*
* \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
*/
-int view3d_opengl_select(ViewContext *vc,
- uint *buffer,
- uint bufsize,
- const rcti *input,
- eV3DSelectMode select_mode,
- eV3DSelectObjectFilter select_filter)
+int view3d_opengl_select_ex(ViewContext *vc,
+ uint *buffer,
+ uint bufsize,
+ const rcti *input,
+ eV3DSelectMode select_mode,
+ eV3DSelectObjectFilter select_filter,
+ const bool do_material_slot_selection)
{
struct bThemeState theme_state;
const wmWindowManager *wm = CTX_wm_manager(vc->C);
@@ -1119,6 +1106,7 @@ int view3d_opengl_select(ViewContext *vc,
use_obedit_skip,
draw_surface,
use_nearest,
+ do_material_slot_selection,
&rect,
drw_select_loop_pass,
&drw_select_loop_user_data,
@@ -1149,6 +1137,7 @@ int view3d_opengl_select(ViewContext *vc,
use_obedit_skip,
draw_surface,
use_nearest,
+ do_material_slot_selection,
&rect,
drw_select_loop_pass,
&drw_select_loop_user_data,
@@ -1178,6 +1167,16 @@ finally:
return hits;
}
+int view3d_opengl_select(ViewContext *vc,
+ uint *buffer,
+ uint bufsize,
+ const rcti *input,
+ eV3DSelectMode select_mode,
+ eV3DSelectObjectFilter select_filter)
+{
+ return view3d_opengl_select_ex(vc, buffer, bufsize, input, select_mode, select_filter, false);
+}
+
int view3d_opengl_select_with_id_filter(ViewContext *vc,
uint *buffer,
uint bufsize,
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 013c5faa54a..d1a1937cef1 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -618,9 +618,6 @@ typedef struct TransInfo {
O_SET,
} orient_curr;
- /** backup from view3d, to restore on end. */
- short gizmo_flag;
-
short prop_mode;
/** Value taken as input, either through mouse coordinates or entered as a parameter. */
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
index 075db30fa61..a6658ae00a3 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -51,7 +51,10 @@
/* helper struct for gp-frame transforms */
typedef struct tGPFtransdata {
- float val; /* where transdata writes transform */
+ union {
+ float val; /* where transdata writes transform */
+ float loc[3]; /* #td->val and #td->loc share the same pointer. */
+ };
int *sdata; /* pointer to gpf->framenum */
} tGPFtransdata;
@@ -245,8 +248,8 @@ static int GPLayerToTransData(TransData *td,
tfd->val = (float)gpf->framenum;
tfd->sdata = &gpf->framenum;
- td->val = td->loc = &tfd->val; /* XXX: It's not a 3d array. */
- td->ival = td->iloc[0] = (float)gpf->framenum;
+ td->val = td->loc = &tfd->val;
+ td->ival = td->iloc[0] = tfd->val;
td->center[0] = td->ival;
td->center[1] = ypos;
@@ -279,16 +282,15 @@ static int MaskLayerToTransData(TransData *td,
masklay_shape = masklay_shape->next) {
if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
- /* memory is calloc'ed, so that should zero everything nicely for us */
- td->val = &tfd->val;
- td->ival = (float)masklay_shape->frame;
+ tfd->val = (float)masklay_shape->frame;
+ tfd->sdata = &masklay_shape->frame;
+
+ td->val = td->loc = &tfd->val;
+ td->ival = td->iloc[0] = tfd->val;
td->center[0] = td->ival;
td->center[1] = ypos;
- tfd->val = (float)masklay_shape->frame;
- tfd->sdata = &masklay_shape->frame;
-
/* advance td now */
td++;
tfd++;
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 5627a910ab4..8f896512410 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -145,30 +145,26 @@ static void autokeyframe_pose(
if (act) {
for (fcu = act->curves.first; fcu; fcu = fcu->next) {
/* only insert keyframes for this F-Curve if it affects the current bone */
- if (strstr(fcu->rna_path, "bones") == NULL) {
+ char pchan_name[sizeof(pchan->name)];
+ if (!BLI_str_quoted_substr(fcu->rna_path, "bones[", pchan_name, sizeof(pchan_name))) {
continue;
}
- char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
/* only if bone name matches too...
* NOTE: this will do constraints too, but those are ok to do here too?
*/
- if (pchanName) {
- if (STREQ(pchanName, pchan->name)) {
- insert_keyframe(bmain,
- reports,
- id,
- act,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
- fcu->array_index,
- &anim_eval_context,
- ts->keyframe_type,
- &nla_cache,
- flag);
- }
-
- MEM_freeN(pchanName);
+ if (STREQ(pchan_name, pchan->name)) {
+ insert_keyframe(bmain,
+ reports,
+ id,
+ act,
+ ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path,
+ fcu->array_index,
+ &anim_eval_context,
+ ts->keyframe_type,
+ &nla_cache,
+ flag);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 9548498f0b8..a2698b342d0 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -265,7 +265,7 @@ static void free_transform_custom_data(TransCustomData *custom_data)
/* Canceled, need to update the strips display. */
static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips)
{
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene, false));
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene));
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
@@ -346,7 +346,7 @@ static bool seq_transform_check_strip_effects(SeqCollection *transformed_strips)
static ListBase *seqbase_active_get(const TransInfo *t)
{
- Editing *ed = SEQ_editing_get(t->scene, false);
+ Editing *ed = SEQ_editing_get(t->scene);
return SEQ_active_seqbase_get(ed);
}
@@ -589,7 +589,7 @@ static SeqCollection *seq_transform_collection_from_transdata(TransDataContainer
static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
{
- Editing *ed = SEQ_editing_get(t->scene, false);
+ Editing *ed = SEQ_editing_get(t->scene);
if (ed == NULL) {
free_transform_custom_data(custom_data);
return;
@@ -622,7 +622,7 @@ void createTransSeqData(TransInfo *t)
#define XXX_DURIAN_ANIM_TX_HACK
Scene *scene = t->scene;
- Editing *ed = SEQ_editing_get(t->scene, false);
+ Editing *ed = SEQ_editing_get(t->scene);
TransData *td = NULL;
TransData2D *td2d = NULL;
TransDataSeq *tdsq = NULL;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 9f5e74db501..c493b9bd102 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -249,12 +249,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->view = v3d;
t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
- /* turn gizmo off during transform */
- if (t->flag & T_MODAL) {
- t->gizmo_flag = v3d->gizmo_flag;
- v3d->gizmo_flag = V3D_GIZMO_HIDE;
- }
-
if (t->scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) {
t->flag |= T_V3D_ALIGN;
}
@@ -742,13 +736,6 @@ void postTrans(bContext *C, TransInfo *t)
}
}
}
- else if (t->spacetype == SPACE_VIEW3D) {
- View3D *v3d = t->area->spacedata.first;
- /* restore gizmo */
- if (t->flag & T_MODAL) {
- v3d->gizmo_flag = t->gizmo_flag;
- }
- }
if (t->mouse.data) {
MEM_freeN(t->mouse.data);
@@ -791,7 +778,7 @@ static void restoreElement(TransData *td)
{
transdata_restore_basic((TransDataBasic *)td);
- if (td->val) {
+ if (td->val && td->val != td->loc) {
*td->val = td->ival;
}
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 279dca9731d..0fa179c4f74 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -674,7 +674,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
if (ob) {
float mat[3][3];
ED_transform_calc_orientation_from_type_ex(
- C, mat, scene, rv3d, ob, obedit, orient_index, pivot_point);
+ scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, mat);
copy_m4_m3(rv3d->twmat, mat);
}
@@ -1974,8 +1974,8 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
gzgt->name = "3D View: Transform Gizmo";
gzgt->idname = "VIEW3D_GGT_xform_gizmo";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
- WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
+ WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
@@ -2216,8 +2216,8 @@ void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
gzgt->name = "Transform Cage";
gzgt->idname = "VIEW3D_GGT_xform_cage";
- gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
- WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
+ WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
@@ -2459,8 +2459,8 @@ void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
gzgt->name = "Transform Shear";
gzgt->idname = "VIEW3D_GGT_xform_shear";
- gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
- WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
+ WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index 8df95222fa1..b9fb8a86752 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -1232,14 +1232,24 @@ void transform_mode_default_modal_orientation_set(TransInfo *t, int type)
return;
}
+ View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
if ((type == V3D_ORIENT_VIEW) && (t->spacetype == SPACE_VIEW3D) && t->region &&
(t->region->regiontype == RGN_TYPE_WINDOW)) {
+ v3d = t->view;
rv3d = t->region->regiondata;
}
t->orient[O_DEFAULT].type = ED_transform_calc_orientation_from_type_ex(
- NULL, t->orient[O_DEFAULT].matrix, NULL, rv3d, NULL, NULL, type, 0);
+ t->scene,
+ t->view_layer,
+ v3d,
+ rv3d,
+ NULL,
+ NULL,
+ type,
+ V3D_AROUND_CENTER_BOUNDS,
+ t->orient[O_DEFAULT].matrix);
if (t->orient_curr == O_DEFAULT) {
/* Update Orientation. */
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 9638ec8750e..3a4a9342e18 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -911,7 +911,8 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot)
ot->name = "Bend";
ot->description = "Bend selected items between the 3D cursor and the mouse";
ot->idname = OP_BEND;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+ /* Depend on cursor location because the cursor location is used to define the region to bend. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_DEPENDS_ON_CURSOR;
/* api callbacks */
ot->invoke = transform_invoke;
@@ -1091,7 +1092,7 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
ot->name = "Edge Slide";
ot->description = "Slide an edge loop along a mesh";
ot->idname = OP_EDGE_SLIDE;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_DEPENDS_ON_CURSOR;
/* api callbacks */
ot->invoke = transform_invoke;
@@ -1129,7 +1130,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
ot->name = "Vertex Slide";
ot->description = "Slide a vertex along a mesh";
ot->idname = OP_VERT_SLIDE;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_DEPENDS_ON_CURSOR;
/* api callbacks */
ot->invoke = transform_invoke;
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 33f4b06eb0e..1e3acdf1071 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -490,13 +490,14 @@ void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obedit = CTX_data_edit_object(C);
+ View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = region->regiondata;
Object *ob = OBACT(view_layer);
const short orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
const int pivot_point = scene->toolsettings->transform_pivot_point;
ED_transform_calc_orientation_from_type_ex(
- C, r_mat, scene, rv3d, ob, obedit, orient_index, pivot_point);
+ scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, r_mat);
}
/**
@@ -508,15 +509,15 @@ void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3
* - #V3D_ORIENT_LOCAL may contain shear from non-uniform scale in parent/child relationships.
* - #V3D_ORIENT_CUSTOM may have been created from #V3D_ORIENT_LOCAL.
*/
-short ED_transform_calc_orientation_from_type_ex(const bContext *C,
- float r_mat[3][3],
- /* extra args (can be accessed from context) */
- Scene *scene,
- RegionView3D *rv3d,
+short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
+ ViewLayer *view_layer,
+ const View3D *v3d,
+ const RegionView3D *rv3d,
Object *ob,
Object *obedit,
const short orientation_index,
- const int pivot_point)
+ const int pivot_point,
+ float r_mat[3][3])
{
switch (orientation_index) {
case V3D_ORIENT_GIMBAL: {
@@ -528,7 +529,7 @@ short ED_transform_calc_orientation_from_type_ex(const bContext *C,
}
case V3D_ORIENT_NORMAL: {
if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
- ED_getTransformOrientationMatrix(C, ob, obedit, pivot_point, r_mat);
+ ED_getTransformOrientationMatrix(view_layer, v3d, ob, obedit, pivot_point, r_mat);
break;
}
/* No break we define 'normal' as 'local' in Object mode. */
@@ -541,7 +542,7 @@ short ED_transform_calc_orientation_from_type_ex(const bContext *C,
* use the active pones axis for display T33575, this works as expected on a single
* bone and users who select many bones will understand what's going on and what local
* means when they start transforming. */
- ED_getTransformOrientationMatrix(C, ob, obedit, pivot_point, r_mat);
+ ED_getTransformOrientationMatrix(view_layer, v3d, ob, obedit, pivot_point, r_mat);
}
else {
transform_orientations_create_from_axis(r_mat, UNPACK3(ob->obmat));
@@ -604,9 +605,11 @@ short transform_orientation_matrix_get(bContext *C,
Object *ob = CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
Scene *scene = t->scene;
+ View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
if ((t->spacetype == SPACE_VIEW3D) && t->region && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+ v3d = t->view;
rv3d = t->region->regiondata;
if (ob && (ob->mode & OB_MODE_ALL_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
@@ -619,15 +622,7 @@ short transform_orientation_matrix_get(bContext *C,
}
short r_orient_index = ED_transform_calc_orientation_from_type_ex(
- C,
- r_spacemtx,
- /* extra args (can be accessed from context) */
- scene,
- rv3d,
- ob,
- obedit,
- orient_index,
- t->around);
+ scene, t->view_layer, v3d, rv3d, ob, obedit, orient_index, t->around, r_spacemtx);
if (rv3d && (t->options & CTX_PAINT_CURVE)) {
/* Screen space in the 3d region. */
@@ -757,15 +752,14 @@ static uint bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const uint n)
}
#endif
-int getTransformOrientation_ex(const bContext *C,
+int getTransformOrientation_ex(ViewLayer *view_layer,
+ const View3D *v3d,
struct Object *ob,
struct Object *obedit,
float normal[3],
float plane[3],
const short around)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
int result = ORIENTATION_NONE;
const bool activeOnly = (around == V3D_AROUND_ACTIVE);
@@ -1296,12 +1290,16 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3])
/* dummy value, not V3D_AROUND_ACTIVE and not V3D_AROUND_LOCAL_ORIGINS */
short around = V3D_AROUND_CENTER_BOUNDS;
- return getTransformOrientation_ex(C, obact, obedit, normal, plane, around);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ return getTransformOrientation_ex(view_layer, v3d, obact, obedit, normal, plane, around);
}
-void ED_getTransformOrientationMatrix(const bContext *C,
- struct Object *ob,
- struct Object *obedit,
+void ED_getTransformOrientationMatrix(ViewLayer *view_layer,
+ const View3D *v3d,
+ Object *ob,
+ Object *obedit,
const short around,
float r_orientation_mat[3][3])
{
@@ -1310,7 +1308,7 @@ void ED_getTransformOrientationMatrix(const bContext *C,
int type;
- type = getTransformOrientation_ex(C, ob, obedit, normal, plane, around);
+ type = getTransformOrientation_ex(view_layer, v3d, ob, obedit, normal, plane, around);
/* Fallback, when the plane can't be calculated. */
if (ORIENTATION_USE_PLANE(type) && is_zero_v3(plane)) {
diff --git a/source/blender/editors/transform/transform_orientations.h b/source/blender/editors/transform/transform_orientations.h
index de8c9b165c1..1da369c8307 100644
--- a/source/blender/editors/transform/transform_orientations.h
+++ b/source/blender/editors/transform/transform_orientations.h
@@ -58,7 +58,8 @@ enum {
};
#define ORIENTATION_USE_PLANE(ty) ELEM(ty, ORIENTATION_NORMAL, ORIENTATION_EDGE, ORIENTATION_FACE)
-int getTransformOrientation_ex(const struct bContext *C,
+int getTransformOrientation_ex(ViewLayer *view_layer,
+ const View3D *v3d,
struct Object *ob,
struct Object *obedit,
float normal[3],
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index bb04f557074..811f30c96e5 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -501,9 +501,7 @@ static void iter_snap_objects(SnapObjectContext *sctx,
}
Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object);
- if (obj_eval->transflag & OB_DUPLI ||
- (obj_eval->runtime.geometry_set_eval != NULL &&
- BKE_geometry_set_has_instances(obj_eval->runtime.geometry_set_eval))) {
+ if (obj_eval->transflag & OB_DUPLI || BKE_object_has_geometry_set_instances(obj_eval)) {
ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval);
for (DupliObject *dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
BLI_assert(DEG_is_evaluated_object(dupli_ob->ob));
diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c
index 6e926f36fba..e82a00bcc77 100644
--- a/source/blender/editors/transform/transform_snap_sequencer.c
+++ b/source/blender/editors/transform/transform_snap_sequencer.c
@@ -137,7 +137,7 @@ static SeqCollection *seq_collection_extract_effects(SeqCollection *collection)
static SeqCollection *query_snap_targets(const TransInfo *t, SeqCollection *snap_sources)
{
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene, false));
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene));
const short snap_flag = SEQ_tool_settings_snap_flag_get(t->scene);
SeqCollection *snap_targets = SEQ_collection_create(__func__);
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
@@ -255,12 +255,12 @@ static int seq_snap_threshold_get_frame_distance(const TransInfo *t)
TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t)
{
TransSeqSnapData *snap_data = MEM_callocN(sizeof(TransSeqSnapData), __func__);
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene, false));
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene));
SeqCollection *snap_sources = SEQ_query_selected_strips(seqbase);
SeqCollection *snap_targets = query_snap_targets(t, snap_sources);
- if (SEQ_collection_len(snap_sources) == 0 || SEQ_collection_len(snap_targets) == 0) {
+ if (SEQ_collection_len(snap_sources) == 0) {
SEQ_collection_free(snap_targets);
SEQ_collection_free(snap_sources);
MEM_freeN(snap_data);
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 3e0029156c1..22064e04e86 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -574,7 +574,12 @@ static bool ed_undo_is_init_poll(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
if (wm->undo_stack == NULL) {
- CTX_wm_operator_poll_msg_set(C, "Undo disabled at startup");
+ /* This message is intended for Python developers,
+ * it will be part of the exception when attempting to call undo in background mode. */
+ CTX_wm_operator_poll_msg_set(
+ C,
+ "Undo disabled at startup in background-mode "
+ "(call `ed.undo_push()` to explicitly initialize the undo-system)");
return false;
}
return true;
diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c
index 9e05efca3df..fcbc0807893 100644
--- a/source/blender/editors/util/ed_util_imbuf.c
+++ b/source/blender/editors/util/ed_util_imbuf.c
@@ -565,7 +565,7 @@ bool ED_imbuf_sample_poll(bContext *C)
return false;
}
- return sseq && SEQ_editing_get(CTX_data_scene(C), false) != NULL;
+ return sseq && SEQ_editing_get(CTX_data_scene(C)) != NULL;
}
return false;
diff --git a/source/blender/editors/uvedit/uvedit_rip.c b/source/blender/editors/uvedit/uvedit_rip.c
index 631b831411f..7e4b18340c5 100644
--- a/source/blender/editors/uvedit/uvedit_rip.c
+++ b/source/blender/editors/uvedit/uvedit_rip.c
@@ -953,7 +953,7 @@ void UV_OT_rip(wmOperatorType *ot)
ot->name = "UV Rip";
ot->description = "Rip selected vertices or a selected region";
ot->idname = "UV_OT_rip";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* api callbacks */
ot->exec = uv_rip_exec;
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 5a82cd31112..c0ccf1b7095 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -3450,7 +3450,7 @@ void UV_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
/* properties */
WM_operator_properties_gesture_lasso(ot);