diff options
author | Joseph Eagar <joeedh@gmail.com> | 2021-09-18 02:22:10 +0300 |
---|---|---|
committer | Joseph Eagar <joeedh@gmail.com> | 2021-09-18 02:22:10 +0300 |
commit | 85d274a60c03b067efaddeda921f0edf1c0982b3 (patch) | |
tree | bb78b124f2d05e3ebe6e3f5a2363d89fe012ecfe /source/blender/editors | |
parent | 6648f82ef7d6a15c8e8fb5474bdee6d2e7853a26 (diff) | |
parent | 6cf734a2e5d2496d1b2d33bc7613b56a9f9fc2ec (diff) |
Merge branch 'master' into sculpt-dev
Diffstat (limited to 'source/blender/editors')
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, ¶ms, 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, ¶ms, 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 = ®ion->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 ¶ms, 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); |