diff options
Diffstat (limited to 'source/blender/editors')
213 files changed, 6740 insertions, 3250 deletions
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt index 1f5dc73f732..a2ae350ce4b 100644 --- a/source/blender/editors/CMakeLists.txt +++ b/source/blender/editors/CMakeLists.txt @@ -22,6 +22,7 @@ if(WITH_BLENDER) add_subdirectory(animation) add_subdirectory(armature) + add_subdirectory(asset) add_subdirectory(curve) add_subdirectory(geometry) add_subdirectory(gizmo_library) diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index c70a86eab1d..6cb829d3a23 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -5353,7 +5353,7 @@ void ANIM_channel_draw_widgets(const bContext *C, "", ICON_NONE, offset, - ymid, + rect->ymin, SLIDER_WIDTH, channel_height); UI_but_func_set(but, achannel_setting_slider_nla_curve_cb, ale->id, ale->data); @@ -5411,7 +5411,7 @@ void ANIM_channel_draw_widgets(const bContext *C, "", icon, offset, - ymid, + rect->ymin, ICON_WIDTH, channel_height); } @@ -5437,7 +5437,7 @@ void ANIM_channel_draw_widgets(const bContext *C, "", icon, offset, - ymid, + rect->ymin, ICON_WIDTH, channel_height); } @@ -5457,7 +5457,7 @@ void ANIM_channel_draw_widgets(const bContext *C, "", ICON_NONE, offset, - ymid, + rect->ymin, width, channel_height); } @@ -5483,7 +5483,7 @@ void ANIM_channel_draw_widgets(const bContext *C, "", ICON_NONE, offset, - ymid, + rect->ymin, SLIDER_WIDTH, channel_height); diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index ba3796ad245..124992bed71 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -49,6 +49,7 @@ #include "BKE_gpencil.h" #include "BKE_lib_id.h" #include "BKE_mask.h" +#include "BKE_nla.h" #include "BKE_scene.h" #include "DEG_depsgraph.h" @@ -1063,18 +1064,27 @@ static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, eAnim_ChannelType type) { ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale, *ale_next; - int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + eAnimFilter_Flags filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_LIST_CHANNELS); /* get all visible channels */ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* now, only keep the ones that are of the types we are interested in */ - for (ale = anim_data.first; ale; ale = ale_next) { - ale_next = ale->next; - + LISTBASE_FOREACH_MUTABLE (bAnimListElem *, ale, &anim_data) { if (ale->type != type) { BLI_freelinkN(&anim_data, ale); + continue; + } + + if (type == ANIMTYPE_NLATRACK) { + NlaTrack *nlt = (NlaTrack *)ale->data; + + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No re-arrangement of non-local tracks of override data. */ + BLI_freelinkN(&anim_data, ale); + continue; + } } } @@ -1146,6 +1156,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn { AnimChanRearrangeFp rearrange_func; ListBase anim_data_visible = {NULL, NULL}; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ac->obact); /* hack: invert mode so that functions will work in right order */ mode *= -1; @@ -1156,6 +1167,29 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn return; } + /* In liboverride case, we need to extract non-local NLA tracks from current anim data before we + * can perform the move, and add then back afterwards. It's the only way to prevent them from + * being affected by the reordering. + * + * Note that both override apply code for NLA tracks collection, and NLA editing code, are + * responsible to ensure that non-local tracks always remain first in the list. */ + ListBase extracted_nonlocal_nla_tracks = {NULL, NULL}; + if (is_liboverride) { + NlaTrack *nla_track; + for (nla_track = adt->nla_tracks.first; nla_track != NULL; nla_track = nla_track->next) { + if (!BKE_nlatrack_is_nonlocal_in_liboverride(&ac->obact->id, nla_track)) { + break; + } + } + if (nla_track != NULL && nla_track->prev != NULL) { + extracted_nonlocal_nla_tracks.first = adt->nla_tracks.first; + extracted_nonlocal_nla_tracks.last = nla_track->prev; + adt->nla_tracks.first = nla_track; + nla_track->prev->next = NULL; + nla_track->prev = NULL; + } + } + /* Filter visible data. */ rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLATRACK); @@ -1163,6 +1197,14 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn rearrange_animchannel_islands( &adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible); + /* Add back non-local NLA tracks at the begining of the animation data's list. */ + if (!BLI_listbase_is_empty(&extracted_nonlocal_nla_tracks)) { + BLI_assert(is_liboverride); + ((NlaTrack *)extracted_nonlocal_nla_tracks.last)->next = adt->nla_tracks.first; + ((NlaTrack *)adt->nla_tracks.first)->prev = extracted_nonlocal_nla_tracks.last; + adt->nla_tracks.first = extracted_nonlocal_nla_tracks.first; + } + /* free temp data */ BLI_freelistN(&anim_data_visible); } diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index e552a321bca..17251587d3b 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -50,6 +50,7 @@ #include "RNA_access.h" #include "SEQ_sequencer.h" +#include "SEQ_utils.h" #include "ED_anim_api.h" @@ -212,15 +213,17 @@ static void animchan_sync_fcurve_scene(bAnimListElem *ale) return; } - Editing *ed = BKE_sequencer_editing_get(scene, false); + 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["); - Sequence *seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false); - if (seq_name) { - MEM_freeN(seq_name); + if (seq_name == NULL) { + return; } + Sequence *seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false); + MEM_freeN(seq_name); + if (seq == NULL) { return; } diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 2e65fff69f1..f2022194ed5 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -101,6 +101,7 @@ #include "ED_markers.h" #include "SEQ_sequencer.h" +#include "SEQ_utils.h" #include "UI_resources.h" /* for TH_KEYFRAME_SCALE lookup */ @@ -225,7 +226,7 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction) { /* TODO, other methods to get the mask */ #if 0 - Sequence *seq = BKE_sequencer_active_get(ac->scene); + Sequence *seq = SEQ_select_active_get(ac->scene); MovieClip *clip = ac->scene->clip; struct Mask *mask = seq ? seq->mask : NULL; #endif @@ -1063,13 +1064,12 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id /* only consider if F-Curve involves pose.bones */ if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) { - bPoseChannel *pchan; - char *bone_name; /* get bone-name, and check if this bone is selected */ - bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + 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); } @@ -1104,15 +1104,14 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id /* only consider if F-Curve involves sequence_editor.sequences */ if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = NULL; - char *seq_name; if (ed) { /* get strip name, and check if this strip is selected */ - seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["); - seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false); + 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); } } @@ -1130,13 +1129,12 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id /* check for selected nodes */ if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) { - bNode *node; - char *node_name; + bNode *node = NULL; /* get strip name, and check if this strip is selected */ - node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes["); - node = nodeFindNodebyName(ntree, node_name); + char *node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes["); if (node_name) { + node = nodeFindNodebyName(ntree, node_name); MEM_freeN(node_name); } diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 72103d68b05..5992545bdbe 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -112,7 +112,8 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) char *constName = BLI_str_quoted_substrN(fcu->rna_path, "constraints["); /* assemble the string to display in the UI... */ - structname = BLI_sprintfN("%s : %s", pchanName, constName); + structname = BLI_sprintfN( + "%s : %s", pchanName ? pchanName : "", constName ? constName : ""); free_structname = 1; /* free the temp names */ diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 9e622aea6ab..a5514f6517e 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -56,6 +56,7 @@ #include "DEG_depsgraph_query.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "anim_intern.h" @@ -93,7 +94,7 @@ static void change_frame_apply(bContext *C, wmOperator *op) if (do_snap) { if (CTX_wm_space_seq(C)) { - frame = BKE_sequencer_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false); + frame = SEQ_time_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false); } else { frame = BKE_scene_frame_snap_by_seconds(scene, 1.0, frame); @@ -503,7 +504,7 @@ static void ANIM_OT_previewrange_clear(wmOperatorType *ot) /* identifiers */ ot->name = "Clear Preview Range"; ot->idname = "ANIM_OT_previewrange_clear"; - ot->description = "Clear Preview Range"; + ot->description = "Clear preview range"; /* api callbacks */ ot->exec = previewrange_clear_exec; diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 08b02020f76..6ed9803dbd3 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -767,16 +767,15 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data) * Storing the relevant information here helps avoiding crashes if we undo-repaste. */ if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) { Object *ob = (Object *)aci->id; - bPoseChannel *pchan; - char *bone_name; - bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); - if (pchan) { - aci->is_bone = true; - } + 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); + + if (pchan) { + aci->is_bone = true; + } } } diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 09c33c48170..e8146ca960a 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -2236,20 +2236,18 @@ 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[")) { - bPoseChannel *pchan; - char *bone_name; /* get bone-name, and check if this bone is selected */ - bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + 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); - } - /* delete if bone is selected*/ - if ((pchan) && (pchan->bone)) { - if (pchan->bone->flag & BONE_SELECTED) { - can_delete = true; + /* delete if bone is selected*/ + if ((pchan) && (pchan->bone)) { + if (pchan->bone->flag & BONE_SELECTED) { + can_delete = true; + } } } } @@ -2342,13 +2340,12 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op) * In object mode, we're dealing with the entire object. */ if ((ob->mode & OB_MODE_POSE) && strstr(fcu->rna_path, "pose.bones[\"")) { - bPoseChannel *pchan; - char *bone_name; + bPoseChannel *pchan = NULL; /* get bone-name, and check if this bone is selected */ - bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + 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); } diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index b20d2738bda..f2cb00f67f0 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -1014,7 +1014,7 @@ void ARMATURE_OT_switch_direction(wmOperatorType *ot) /* identifiers */ ot->name = "Switch Direction"; ot->idname = "ARMATURE_OT_switch_direction"; - ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)"; + ot->description = "Change the direction that a chain of bones points in (head and tail swap)"; /* api callbacks */ ot->exec = armature_switch_direction_exec; diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c index c217b615db6..7c11c5e537e 100644 --- a/source/blender/editors/armature/editarmature_undo.c +++ b/source/blender/editors/armature/editarmature_undo.c @@ -26,7 +26,9 @@ #include "CLG_log.h" #include "DNA_armature_types.h" +#include "DNA_layer_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BLI_array_utils.h" #include "BLI_listbase.h" diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 731d0d10e0b..6a03207b3b0 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -1090,6 +1090,7 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, bool ex 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 */ @@ -1098,9 +1099,6 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, bool ex changed = true; } } - - /* free temp memory */ - MEM_freeN(boneName); } } } diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt new file mode 100644 index 00000000000..63a1761b264 --- /dev/null +++ b/source/blender/editors/asset/CMakeLists.txt @@ -0,0 +1,39 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# ***** END GPL LICENSE BLOCK ***** + +set(INC + ../include + ../../blenlib + ../../blenkernel + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/guardedalloc +) + +set(INC_SYS +) + +set(SRC + asset_edit.c + asset_ops.c +) + +set(LIB +) + +blender_add_lib(bf_editor_asset "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/asset/asset_edit.c b/source/blender/editors/asset/asset_edit.c new file mode 100644 index 00000000000..5333c08c66a --- /dev/null +++ b/source/blender/editors/asset/asset_edit.c @@ -0,0 +1,69 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edasset + */ + +#include "BKE_asset.h" +#include "BKE_context.h" +#include "BKE_idtype.h" +#include "BKE_lib_id.h" + +#include "DNA_ID.h" +#include "DNA_asset_types.h" + +#include "UI_interface_icons.h" + +#include "RNA_access.h" + +#include "ED_asset.h" + +bool ED_asset_mark_id(const bContext *C, ID *id) +{ + if (id->asset_data) { + return false; + } + if (!BKE_id_can_be_asset(id)) { + return false; + } + + id_fake_user_set(id); + + id->asset_data = BKE_asset_metadata_create(); + + UI_icon_render_id(C, NULL, id, true, true); + + return true; +} + +bool ED_asset_clear_id(ID *id) +{ + if (!id->asset_data) { + return false; + } + BKE_asset_metadata_free(&id->asset_data); + /* Don't clear fake user here, there's no guarantee that it was actually set by + * #ED_asset_mark_id(), it might have been something/someone else. */ + + return true; +} + +bool ED_asset_can_make_single_from_context(const bContext *C) +{ + /* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */ + return CTX_data_pointer_get_type_silent(C, "id", &RNA_ID).data != NULL; +} diff --git a/source/blender/editors/asset/asset_ops.c b/source/blender/editors/asset/asset_ops.c new file mode 100644 index 00000000000..929d49e19fa --- /dev/null +++ b/source/blender/editors/asset/asset_ops.c @@ -0,0 +1,238 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edasset + */ + +#include <string.h> + +#include "BKE_asset.h" +#include "BKE_context.h" +#include "BKE_report.h" + +#include "BLI_listbase.h" +#include "BLI_string_utils.h" + +#include "DNA_asset_types.h" + +#include "ED_asset.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +/* -------------------------------------------------------------------- */ + +struct AssetMarkResultStats { + int tot_created; + int tot_already_asset; + ID *last_id; +}; + +/** + * Return the IDs to operate on as list of #CollectionPointerLink links. Needs freeing. + */ +static ListBase /* CollectionPointerLink */ asset_operation_get_ids_from_context(const bContext *C) +{ + ListBase list = {0}; + + PointerRNA idptr = CTX_data_pointer_get_type(C, "id", &RNA_ID); + + if (idptr.data) { + CollectionPointerLink *ctx_link = MEM_callocN(sizeof(*ctx_link), __func__); + ctx_link->ptr = idptr; + BLI_addtail(&list, ctx_link); + } + else { + CTX_data_selected_ids(C, &list); + } + + return list; +} + +static void asset_mark_for_idptr_list(const bContext *C, + const ListBase /* CollectionPointerLink */ *ids, + struct AssetMarkResultStats *r_stats) +{ + memset(r_stats, 0, sizeof(*r_stats)); + + LISTBASE_FOREACH (CollectionPointerLink *, ctx_id, ids) { + BLI_assert(RNA_struct_is_ID(ctx_id->ptr.type)); + + ID *id = ctx_id->ptr.data; + if (id->asset_data) { + r_stats->tot_already_asset++; + continue; + } + + if (ED_asset_mark_id(C, id)) { + r_stats->last_id = id; + r_stats->tot_created++; + } + } +} + +static bool asset_mark_results_report(const struct AssetMarkResultStats *stats, + ReportList *reports) +{ + /* User feedback on failure. */ + if ((stats->tot_created < 1) && (stats->tot_already_asset > 0)) { + BKE_report(reports, + RPT_ERROR, + "Selected data-blocks are already assets (or do not support use as assets)"); + return false; + } + if (stats->tot_created < 1) { + BKE_report(reports, + RPT_ERROR, + "No data-blocks to create assets for found (or do not support use as assets)"); + return false; + } + + /* User feedback on success. */ + if (stats->tot_created == 1) { + /* If only one data-block: Give more useful message by printing asset name. */ + BKE_reportf(reports, RPT_INFO, "Data-block '%s' is now an asset", stats->last_id->name + 2); + } + else { + BKE_reportf(reports, RPT_INFO, "%i data-blocks are now assets", stats->tot_created); + } + + return true; +} + +static int asset_mark_exec(bContext *C, wmOperator *op) +{ + ListBase ids = asset_operation_get_ids_from_context(C); + + struct AssetMarkResultStats stats; + asset_mark_for_idptr_list(C, &ids, &stats); + BLI_freelistN(&ids); + + if (!asset_mark_results_report(&stats, op->reports)) { + return OPERATOR_CANCELLED; + } + + WM_main_add_notifier(NC_ID | NA_EDITED, NULL); + WM_main_add_notifier(NC_ASSET | NA_ADDED, NULL); + + return OPERATOR_FINISHED; +} + +static void ASSET_OT_mark(wmOperatorType *ot) +{ + ot->name = "Mark Asset"; + ot->description = + "Enable easier reuse of selected data-blocks through the Asset Browser, with the help of " + "customizable metadata (like previews, descriptions and tags)"; + ot->idname = "ASSET_OT_mark"; + + ot->exec = asset_mark_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* -------------------------------------------------------------------- */ + +struct AssetClearResultStats { + int tot_removed; + ID *last_id; +}; + +static void asset_clear_from_idptr_list(const ListBase /* CollectionPointerLink */ *ids, + struct AssetClearResultStats *r_stats) +{ + memset(r_stats, 0, sizeof(*r_stats)); + + LISTBASE_FOREACH (CollectionPointerLink *, ctx_id, ids) { + BLI_assert(RNA_struct_is_ID(ctx_id->ptr.type)); + + ID *id = ctx_id->ptr.data; + if (!id->asset_data) { + continue; + } + + if (ED_asset_clear_id(id)) { + r_stats->tot_removed++; + r_stats->last_id = id; + } + } +} + +static bool asset_clear_result_report(const struct AssetClearResultStats *stats, + ReportList *reports) + +{ + if (stats->tot_removed < 1) { + BKE_report(reports, RPT_ERROR, "No asset data-blocks selected/focused"); + return false; + } + + if (stats->tot_removed == 1) { + /* If only one data-block: Give more useful message by printing asset name. */ + BKE_reportf( + reports, RPT_INFO, "Data-block '%s' is no asset anymore", stats->last_id->name + 2); + } + else { + BKE_reportf(reports, RPT_INFO, "%i data-blocks are no assets anymore", stats->tot_removed); + } + + return true; +} + +static int asset_clear_exec(bContext *C, wmOperator *op) +{ + ListBase ids = asset_operation_get_ids_from_context(C); + + struct AssetClearResultStats stats; + asset_clear_from_idptr_list(&ids, &stats); + BLI_freelistN(&ids); + + if (!asset_clear_result_report(&stats, op->reports)) { + return OPERATOR_CANCELLED; + } + + WM_main_add_notifier(NC_ID | NA_EDITED, NULL); + WM_main_add_notifier(NC_ASSET | NA_REMOVED, NULL); + + return OPERATOR_FINISHED; +} + +static void ASSET_OT_clear(wmOperatorType *ot) +{ + ot->name = "Clear Asset"; + ot->description = + "Delete all asset metadata and turn the selected asset data-blocks back into normal " + "data-blocks"; + ot->idname = "ASSET_OT_clear"; + + ot->exec = asset_clear_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* -------------------------------------------------------------------- */ + +void ED_operatortypes_asset(void) +{ + WM_operatortype_append(ASSET_OT_mark); + WM_operatortype_append(ASSET_OT_clear); +} diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index db472c9ffa7..2b627971286 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -3838,7 +3838,7 @@ void CURVE_OT_subdivide(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of cuts", "", 1, 10); + prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of Cuts", "", 1, 10); /* Avoid re-using last var because it can cause _very_ high poly meshes * and annoy users (or worse crash). */ RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 361c5d4048e..6ec7fbe80b6 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -657,6 +657,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES brush.sculpt.mask brush.sculpt.multiplane_scrape brush.sculpt.nudge + brush.sculpt.paint brush.sculpt.pinch brush.sculpt.pose brush.sculpt.rotate diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c index f7caf8e4c6a..8755dea51e1 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c @@ -50,7 +50,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "wm.h" /* own includes */ #include "../gizmo_geometry.h" @@ -66,7 +65,13 @@ typedef struct SnapGizmo3D { /* We could have other snap contexts, for now only support 3D view. */ SnapObjectContext *snap_context_v3d; - int mval[2]; + + /* Copy of the parameters of the last event state in order to detect updates. */ + struct { + int x; + int y; + short shift, ctrl, alt, oskey; + } last_eventstate; #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK wmKeyMap *keymap; @@ -77,6 +82,37 @@ typedef struct SnapGizmo3D { short snap_elem; } SnapGizmo3D; +/* Checks if the current event is different from the one captured in the last update. */ +static bool eventstate_has_changed(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) +{ + if (wm && wm->winactive) { + const wmEvent *event = wm->winactive->eventstate; + if ((event->x != snap_gizmo->last_eventstate.x) || + (event->y != snap_gizmo->last_eventstate.y) || + (event->ctrl != snap_gizmo->last_eventstate.ctrl) || + (event->shift != snap_gizmo->last_eventstate.shift) || + (event->alt != snap_gizmo->last_eventstate.alt) || + (event->oskey != snap_gizmo->last_eventstate.oskey)) { + return true; + } + } + return false; +} + +/* Copies the current eventstate. */ +static void eventstate_save(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) +{ + if (wm && wm->winactive) { + const wmEvent *event = wm->winactive->eventstate; + snap_gizmo->last_eventstate.x = event->x; + snap_gizmo->last_eventstate.y = event->y; + snap_gizmo->last_eventstate.ctrl = event->ctrl; + snap_gizmo->last_eventstate.shift = event->shift; + snap_gizmo->last_eventstate.alt = event->alt; + snap_gizmo->last_eventstate.oskey = event->oskey; + } +} + #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) { @@ -84,6 +120,15 @@ static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) return false; } + const wmEvent *event = wm->winactive->eventstate; + if ((event->ctrl == snap_gizmo->last_eventstate.ctrl) && + (event->shift == snap_gizmo->last_eventstate.shift) && + (event->alt == snap_gizmo->last_eventstate.alt) && + (event->oskey == snap_gizmo->last_eventstate.oskey)) { + /* Nothing has changed. */ + return snap_gizmo->invert_snap; + } + if (snap_gizmo->keymap == NULL) { /* Lazy initialization. */ snap_gizmo->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map"); @@ -92,7 +137,6 @@ static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) const int snap_on = snap_gizmo->snap_on; wmKeyMap *keymap = WM_keymap_active(wm, snap_gizmo->keymap); - const wmEvent *event = wm->winactive->eventstate; for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { if (kmi->flag & KMI_INACTIVE) { continue; @@ -250,12 +294,6 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, float r_nor[3]) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - Scene *scene = DEG_get_input_scene(depsgraph); - float co[3], no[3]; - short snap_elem = 0; - int snap_elem_index[3] = {-1, -1, -1}; - int index = -1; - if (snap_gizmo->use_snap_override != -1) { if (snap_gizmo->use_snap_override == false) { snap_gizmo->snap_elem = 0; @@ -265,7 +303,12 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK snap_gizmo->invert_snap = invert_snap(snap_gizmo, wm); +#endif + eventstate_save(snap_gizmo, wm); + Scene *scene = DEG_get_input_scene(depsgraph); + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK if (snap_gizmo->use_snap_override == -1) { const ToolSettings *ts = scene->toolsettings; if (snap_gizmo->invert_snap != !(ts->snap_flag & SCE_SNAP)) { @@ -273,10 +316,13 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, return 0; } } -#else - UNUSED_VARS(wm); #endif + float co[3], no[3]; + short snap_elem = 0; + int snap_elem_index[3] = {-1, -1, -1}; + int index = -1; + wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "snap_elements"); int snap_elements = RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop); if (gz_prop->prop != snap_gizmo->prop_snap_force) { @@ -381,14 +427,17 @@ static void snap_gizmo_draw(const bContext *C, wmGizmo *gz) return; } - ARegion *region = CTX_wm_region(C); - RegionView3D *rv3d = region->regiondata; + wmWindowManager *wm = CTX_wm_manager(C); + if (eventstate_has_changed(snap_gizmo, wm)) { + /* The eventstate has changed but the snap has not been updated. + * This means that the current position is no longer valid. */ + snap_gizmo->snap_elem = 0; + return; + } - /* Ideally, we shouldn't assign values here. - * But `test_select` is not called during navigation. - * And `snap_elem` is not really useful in this case. */ - if ((rv3d->rflag & RV3D_NAVIGATING) || - (!(gz->state & WM_GIZMO_STATE_HIGHLIGHT) && !wm_gizmomap_modal_get(region->gizmo_map))) { + RegionView3D *rv3d = CTX_wm_region_data(C); + if (rv3d->rflag & RV3D_NAVIGATING) { + /* Don't draw the gizmo while navigating. It can be distracting. */ snap_gizmo->snap_elem = 0; return; } @@ -418,30 +467,17 @@ static void snap_gizmo_draw(const bContext *C, wmGizmo *gz) static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2]) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - -#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK wmWindowManager *wm = CTX_wm_manager(C); - const bool invert = invert_snap(snap_gizmo, wm); - if (snap_gizmo->invert_snap == invert && snap_gizmo->mval[0] == mval[0] && - snap_gizmo->mval[1] == mval[1]) { + if (!eventstate_has_changed(snap_gizmo, wm)) { /* Performance, do not update. */ return snap_gizmo->snap_elem ? 0 : -1; } - snap_gizmo->invert_snap = invert; -#else - if (snap_gizmo->mval[0] == mval[0] && snap_gizmo->mval[1] == mval[1]) { - /* Performance, do not update. */ - return snap_gizmo->snap_elem ? 0 : -1; - } -#endif - copy_v2_v2_int(snap_gizmo->mval, mval); - ARegion *region = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); const float mval_fl[2] = {UNPACK2(mval)}; short snap_elem = ED_gizmotypes_snap_3d_update( - gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, mval_fl, NULL, NULL); + gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, wm, mval_fl, NULL, NULL); if (snap_elem) { ED_region_tag_redraw_editor_overlays(region); diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 93767127cc7..4e2951c3571 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -41,6 +41,7 @@ #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c index 315b3c281da..65141442237 100644 --- a/source/blender/editors/gpencil/gpencil_add_monkey.c +++ b/source/blender/editors/gpencil/gpencil_add_monkey.c @@ -25,6 +25,7 @@ #include "BLI_utildefines.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c index f26fd936d40..0c8cc621a3b 100644 --- a/source/blender/editors/gpencil/gpencil_add_stroke.c +++ b/source/blender/editors/gpencil/gpencil_add_stroke.c @@ -25,6 +25,7 @@ #include "BLI_utildefines.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 63aa242275a..09b57029350 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -41,6 +41,7 @@ #include "DNA_collection_types.h" #include "DNA_curve_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 33a1469beab..aff109eb98e 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -42,6 +42,7 @@ #include "DNA_anim_types.h" #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" @@ -1330,19 +1331,24 @@ static int gpencil_merge_layer_exec(bContext *C, wmOperator *op) BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst); } - /* Read all frames from merge layer and add any missing in destination layer. */ + /* Read all frames from merge layer and add any missing in destination layer, + * copying all previous strokes to keep the image equals. + * Need to do it in a separated loop to avoid strokes accumulation. */ LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { /* Try to find frame in destination layer hash table. */ bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); if (!gpf_dst) { - gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum); - /* Duplicate strokes into destination frame. */ - if (gpf_dst) { - BKE_gpencil_frame_copy_strokes(gpf_src, gpf_dst); - } + gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY); + BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst); } - else { - /* Add to tail all strokes. */ + } + + /* Read all frames from merge layer and add strokes. */ + LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { + /* Try to find frame in destination layer hash table. */ + bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); + /* Add to tail all strokes. */ + if (gpf_dst) { BLI_movelisttolist(&gpf_dst->strokes, &gpf_src->strokes); } } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 95c94f8cfed..36e383cf3c2 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -41,6 +41,7 @@ #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 93941ea3766..39968aac9fa 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -35,6 +35,7 @@ #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" #include "DNA_image_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_windowmanager_types.h" diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 3617f20763e..1c967110198 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -283,8 +283,8 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer"); tgpil->gpl = gpl; - tgpil->prevFrame = gpl->actframe; - tgpil->nextFrame = gpl->actframe->next; + tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe); + tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next); BLI_addtail(&tgpi->ilayers, tgpil); @@ -326,24 +326,25 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) valid = false; } - /* create new stroke */ - new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); - if (valid) { /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { - new_stroke->points = MEM_recallocN(new_stroke->points, - sizeof(*new_stroke->points) * gps_to->totpoints); - if (new_stroke->dvert != NULL) { - new_stroke->dvert = MEM_recallocN(new_stroke->dvert, - sizeof(*new_stroke->dvert) * gps_to->totpoints); - } - new_stroke->totpoints = gps_to->totpoints; + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true); } - /* update points position */ + if (gps_to->totpoints > gps_from->totpoints) { + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true); + } + + /* Create new stroke. */ + new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); + + /* Update points position. */ gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor); } else { + /* Create new stroke. */ + new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); + /* need an empty stroke to keep index correct for lookup, but resize to smallest size */ new_stroke->totpoints = 0; new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points)); @@ -443,12 +444,16 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) /* finally, free memory used by temp data */ LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) { + BKE_gpencil_free_strokes(tgpil->prevFrame); + BKE_gpencil_free_strokes(tgpil->nextFrame); BKE_gpencil_free_strokes(tgpil->interFrame); - MEM_freeN(tgpil->interFrame); + MEM_SAFE_FREE(tgpil->prevFrame); + MEM_SAFE_FREE(tgpil->nextFrame); + MEM_SAFE_FREE(tgpil->interFrame); } BLI_freelistN(&tgpi->ilayers); - MEM_freeN(tgpi); + MEM_SAFE_FREE(tgpi); } DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); @@ -478,14 +483,15 @@ static bool gpencil_interpolate_set_init_values(bContext *C, wmOperator *op, tGP /* set interpolation weight */ tgpi->shift = RNA_float_get(op->ptr, "shift"); - /* set layers */ - gpencil_interpolate_set_points(C, tgpi); /* Untag strokes to be sure nothing is pending due any canceled process. */ LISTBASE_FOREACH (bGPDlayer *, gpl, &tgpi->gpd->layers) { gpencil_interpolate_untag_strokes(gpl); } + /* Set layers */ + gpencil_interpolate_set_points(C, tgpi); + return 1; } @@ -992,8 +998,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } /* store extremes */ - prevFrame = gpl->actframe; - nextFrame = gpl->actframe->next; + prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe); + nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next); /* Loop over intermediary frames and create the interpolation */ for (cframe = prevFrame->framenum + step; cframe < nextFrame->framenum; cframe += step) { @@ -1049,28 +1055,17 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN; } - /* create new stroke */ - bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); - /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { - /* free weights of removed points */ - if (new_stroke->dvert != NULL) { - BKE_defvert_array_free_elems(new_stroke->dvert + gps_to->totpoints, - gps_from->totpoints - gps_to->totpoints); - } - - new_stroke->points = MEM_recallocN(new_stroke->points, - sizeof(*new_stroke->points) * gps_to->totpoints); - - if (new_stroke->dvert != NULL) { - new_stroke->dvert = MEM_recallocN(new_stroke->dvert, - sizeof(*new_stroke->dvert) * gps_to->totpoints); - } - - new_stroke->totpoints = gps_to->totpoints; + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true); + } + if (gps_to->totpoints > gps_from->totpoints) { + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true); } + /* create new stroke */ + bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); + /* update points position */ gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor); @@ -1081,6 +1076,11 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) BLI_addtail(&interFrame->strokes, new_stroke); } } + + BKE_gpencil_free_strokes(prevFrame); + BKE_gpencil_free_strokes(nextFrame); + MEM_SAFE_FREE(prevFrame); + MEM_SAFE_FREE(nextFrame); } /* notifiers */ diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 9f2bf3818a4..272dff56291 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -31,6 +31,7 @@ #include "BLI_math.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "BKE_brush.h" #include "BKE_context.h" diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c index 4721736489e..815bbbaa254 100644 --- a/source/blender/editors/gpencil/gpencil_ops_versioning.c +++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c @@ -33,6 +33,7 @@ #include "BLI_math.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index ed18c2eed5d..bb9dd8cac5d 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -41,6 +41,7 @@ #include "BLT_translation.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 2c0b9534141..281ab8c5adc 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -36,6 +36,7 @@ #include "BLI_utildefines.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index e8e25a55796..c3ac33063af 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -40,7 +40,9 @@ #include "PIL_time.h" #include "DNA_brush_types.h" +#include "DNA_collection_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index c3fd8d10b64..b212872b607 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -32,6 +32,7 @@ #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "BKE_colortools.h" #include "BKE_context.h" @@ -236,7 +237,7 @@ void GPENCIL_OT_vertex_color_brightness_contrast(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Vertex Paint Bright/Contrast"; + ot->name = "Vertex Paint Brightness/Contrast"; ot->idname = "GPENCIL_OT_vertex_color_brightness_contrast"; ot->description = "Adjust vertex color brightness/contrast"; diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index a4dc677f0dc..3afff897734 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -31,6 +31,7 @@ #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "BKE_brush.h" #include "BKE_colortools.h" diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 3501acd4fdf..0c4576096fb 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -31,7 +31,6 @@ struct Base; struct Bone; struct Depsgraph; struct EditBone; -struct IDProperty; struct ListBase; struct Main; struct Mesh; diff --git a/source/blender/editors/include/ED_asset.h b/source/blender/editors/include/ED_asset.h new file mode 100644 index 00000000000..6fe50528cc5 --- /dev/null +++ b/source/blender/editors/include/ED_asset.h @@ -0,0 +1,39 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup editors + */ + +#ifndef __ED_ASSET_H__ +#define __ED_ASSET_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +bool ED_asset_mark_id(const struct bContext *C, struct ID *id); +bool ED_asset_clear_id(struct ID *id); + +bool ED_asset_can_make_single_from_context(const struct bContext *C); + +void ED_operatortypes_asset(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __ED_ASSET_H__ */ diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 84808416074..7b240e0569f 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -28,7 +28,9 @@ extern "C" { #endif struct ARegion; +struct FileAssetSelectParams; struct FileSelectParams; +struct FileDirEntry; struct Scene; struct ScrArea; struct SpaceFile; @@ -101,16 +103,16 @@ typedef struct FileSelection { struct View2D; struct rcti; -struct FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile); +struct FileSelectParams *ED_fileselect_ensure_active_params(struct SpaceFile *sfile); +struct FileSelectParams *ED_fileselect_get_active_params(const struct SpaceFile *sfile); +struct FileSelectParams *ED_fileselect_get_file_params(const struct SpaceFile *sfile); +struct FileAssetSelectParams *ED_fileselect_get_asset_params(const struct SpaceFile *sfile); -short ED_fileselect_set_params(struct SpaceFile *sfile); void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile); void ED_fileselect_params_to_userdef(struct SpaceFile *sfile, const int temp_win_size[], const bool is_maximized); -void ED_fileselect_reset_params(struct SpaceFile *sfile); - void ED_fileselect_init_layout(struct SpaceFile *sfile, struct ARegion *region); FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, struct ARegion *region); @@ -142,6 +144,8 @@ void ED_fileselect_exit(struct wmWindowManager *wm, struct Scene *owner_scene, struct SpaceFile *sfile); +bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile); + void ED_fileselect_window_params_get(const struct wmWindow *win, int win_size[2], bool *is_maximized); @@ -151,6 +155,7 @@ struct ScrArea *ED_fileselect_handler_area_find(const struct wmWindow *win, int ED_path_extension_type(const char *path); int ED_file_extension_icon(const char *path); +int ED_file_icon(const struct FileDirEntry *file); void ED_file_read_bookmarks(void); diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index be2f714dfe1..1b7caf27ecf 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -51,7 +51,6 @@ struct ScrArea; struct SnapObjectContext; struct ToolSettings; struct View3D; -struct ViewLayer; struct bContext; struct Material; diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index c1d3a17b9b6..b139b0765a3 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -34,12 +34,10 @@ struct ARegion; struct ImBuf; struct Image; struct ImageUser; -struct LinkNodePair; struct Main; struct ReportList; struct Scene; struct SpaceImage; -struct ViewLayer; struct bContext; struct wmOperator; struct wmWindowManager; diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h index e3ce494e09a..9ac6b6c1085 100644 --- a/source/blender/editors/include/ED_info.h +++ b/source/blender/editors/include/ED_info.h @@ -38,8 +38,12 @@ const char *ED_info_statistics_string(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer); -void ED_info_draw_stats( - struct Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height); +void ED_info_draw_stats(struct Main *bmain, + struct Scene *scene, + struct ViewLayer *view_layer, + int x, + int *y, + int height); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 2e9b711c99a..f9358f62274 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -53,7 +53,6 @@ struct uiLayout; struct wmKeyConfig; struct wmOperator; struct wmOperatorType; -struct wmWindowManager; /* object_edit.c */ /* context.object */ diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index dc1c43c0337..20417634020 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -239,6 +239,7 @@ void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area); ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type); void ED_screen_full_prevspace(struct bContext *C, ScrArea *area); void ED_screen_full_restore(struct bContext *C, ScrArea *area); +ScrArea *ED_screen_state_maximized_create(struct bContext *C); struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *area, diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 0ea86e006e0..ca3e351a052 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -32,7 +32,6 @@ extern "C" { struct Object; struct bContext; struct wmKeyConfig; -struct wmMsgBus; struct wmOperatorType; void ED_keymap_transform(struct wmKeyConfig *keyconf); @@ -108,7 +107,6 @@ bool calculateTransformCenter(struct bContext *C, struct Object; struct Scene; -struct wmGizmoGroup; struct wmGizmoGroupType; /* UNUSED */ diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index ebaa32941f2..b7174964ef6 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -31,7 +31,6 @@ struct BMVert; struct ARegion; struct Depsgraph; struct ListBase; -struct Main; struct Object; struct Scene; struct View3D; diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 68ae3589064..1e87a940a7d 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -52,7 +52,10 @@ void ED_spacedata_id_remap(struct ScrArea *area, struct ID *old_id, struct ID *new_id); -void ED_OT_flush_edits(struct wmOperatorType *ot); +void ED_OT_lib_id_load_custom_preview(struct wmOperatorType *ot); +void ED_OT_lib_id_generate_preview(struct wmOperatorType *ot); + +void ED_operatortypes_edutils(void); /* ************** XXX OLD CRUFT WARNING ************* */ diff --git a/source/blender/editors/include/ED_util_imbuf.h b/source/blender/editors/include/ED_util_imbuf.h index d142d3d6425..4bbaa68e849 100644 --- a/source/blender/editors/include/ED_util_imbuf.h +++ b/source/blender/editors/include/ED_util_imbuf.h @@ -31,7 +31,6 @@ extern "C" { #endif struct ARegion; -struct Main; struct bContext; struct wmEvent; struct wmOperator; diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 2066d7da511..4de97411059 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -33,7 +33,6 @@ struct BMEditMesh; struct BMFace; struct BMLoop; struct BMesh; -struct Depsgraph; struct Image; struct ImageUser; struct Main; @@ -217,8 +216,10 @@ struct BMLoop *ED_uvedit_active_vert_loop_get(struct BMesh *bm); void ED_uvedit_active_edge_loop_set(struct BMesh *bm, struct BMLoop *l); struct BMLoop *ED_uvedit_active_edge_loop_get(struct BMesh *bm); -char ED_uvedit_select_mode_get(const Scene *scene); -void ED_uvedit_select_sync_flush(const ToolSettings *ts, struct BMEditMesh *em, const bool select); +char ED_uvedit_select_mode_get(const struct Scene *scene); +void ED_uvedit_select_sync_flush(const struct ToolSettings *ts, + struct BMEditMesh *em, + const bool select); /* uvedit_unwrap_ops.c */ void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit); @@ -244,7 +245,7 @@ struct UVPackIsland_Params { uint use_seams : 1; uint correct_aspect : 1; }; -void ED_uvedit_pack_islands_multi(const Scene *scene, +void ED_uvedit_pack_islands_multi(const struct Scene *scene, Object **objects, const uint objects_len, const struct UVPackIsland_Params *params); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 596533406c3..a4856845a65 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -41,8 +41,6 @@ struct Camera; struct CustomData_MeshMasks; struct Depsgraph; struct EditBone; -struct GPUOffScreen; -struct GPUViewport; struct ID; struct MVert; struct Main; @@ -55,7 +53,6 @@ struct RenderEngineType; struct Scene; struct ScrArea; struct View3D; -struct View3DShading; struct ViewContext; struct ViewLayer; struct bContext; @@ -64,8 +61,6 @@ struct bScreen; struct rctf; struct rcti; struct wmGizmo; -struct wmOperator; -struct wmOperatorType; struct wmWindow; struct wmWindowManager; @@ -141,6 +136,11 @@ void ED_view3d_to_object(const struct Depsgraph *depsgraph, const float quat[4], const float dist); +bool ED_view3d_camera_to_view_selected(struct Main *bmain, + struct Depsgraph *depsgraph, + const struct Scene *scene, + struct Object *camera_ob); + void ED_view3d_lastview_store(struct RegionView3D *rv3d); /* Depth buffer */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index faf34573475..79311042274 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -920,6 +920,7 @@ DEF_ICON_COLOR(BRUSH_TEXMASK) DEF_ICON_COLOR(BRUSH_THUMB) DEF_ICON_COLOR(BRUSH_ROTATE) DEF_ICON_COLOR(BRUSH_VCOL_BOUNDARY) +DEF_ICON_COLOR(BRUSH_PAINT) /* grease pencil sculpt */ DEF_ICON_COLOR(GPBRUSH_SMOOTH) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 005dbf0e381..2705dd27756 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -50,7 +50,6 @@ struct PointerRNA; struct PropertyRNA; struct ReportList; struct ResultBLF; -struct ScrArea; struct bContext; struct bContextStore; struct bNode; @@ -77,6 +76,7 @@ struct wmWindow; typedef struct uiBlock uiBlock; typedef struct uiBut uiBut; +typedef struct uiButExtraOpIcon uiButExtraOpIcon; typedef struct uiLayout uiLayout; typedef struct uiPopupBlockHandle uiPopupBlockHandle; @@ -103,14 +103,19 @@ typedef struct uiPopupBlockHandle uiPopupBlockHandle; #define UI_SCREEN_MARGIN 10 /** #uiBlock.emboss and #uiBut.emboss */ -enum { +typedef enum eUIEmbossType { UI_EMBOSS = 0, /* use widget style for drawing */ UI_EMBOSS_NONE = 1, /* Nothing, only icon and/or text */ UI_EMBOSS_PULLDOWN = 2, /* Pulldown menu style */ UI_EMBOSS_RADIAL = 3, /* Pie Menu */ + /** + * The same as #UI_EMBOSS_NONE, unless the the button has + * a coloring status like an animation state or red alert. + */ + UI_EMBOSS_NONE_OR_STATUS = 4, UI_EMBOSS_UNDEFINED = 255, /* For layout engine, use emboss from block. */ -}; +} eUIEmbossType; /* uiBlock->direction */ enum { @@ -666,7 +671,7 @@ bool UI_popup_block_name_exists(const struct bScreen *screen, const char *name); uiBlock *UI_block_begin(const struct bContext *C, struct ARegion *region, const char *name, - char emboss); + eUIEmbossType emboss); void UI_block_end_ex(const struct bContext *C, uiBlock *block, const int xy[2], int r_xy[2]); void UI_block_end(const struct bContext *C, uiBlock *block); void UI_block_draw(const struct bContext *C, struct uiBlock *block); @@ -680,7 +685,7 @@ enum { }; void UI_block_theme_style_set(uiBlock *block, char theme_style); char UI_block_emboss_get(uiBlock *block); -void UI_block_emboss_set(uiBlock *block, char emboss); +void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss); bool UI_block_is_search_only(const uiBlock *block); void UI_block_set_search_only(uiBlock *block, bool search_only); @@ -727,6 +732,13 @@ void UI_block_translate(uiBlock *block, int x, int y); int UI_but_return_value_get(uiBut *but); void UI_but_drag_set_id(uiBut *but, struct ID *id); +void UI_but_drag_set_asset(uiBut *but, + const char *name, + const char *path, + int id_type, + int icon, + struct ImBuf *imb, + float scale); void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr); void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free); void UI_but_drag_set_name(uiBut *but, const char *name); @@ -1375,13 +1387,16 @@ typedef struct uiStringInfo { /* Note: Expects pointers to uiStringInfo structs as parameters. * Will fill them with translated strings, when possible. * Strings in uiStringInfo must be MEM_freeN'ed by caller. */ -void UI_but_string_info_get(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0); +void UI_but_string_info_get(struct bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon, ...) + ATTR_SENTINEL(0); /* Edit i18n stuff. */ /* Name of the main py op from i18n addon. */ #define EDTSRC_I18N_OP_NAME "UI_OT_edittranslation" /** + * TODO This is old stuff, only used by templateID. Should be cleaned up. + * * Special Buttons * * Buttons with a more specific purpose: @@ -1399,14 +1414,16 @@ enum { UI_ID_ALONE = 1 << 4, UI_ID_OPEN = 1 << 3, UI_ID_DELETE = 1 << 5, - UI_ID_LOCAL = 1 << 6, - UI_ID_AUTO_NAME = 1 << 7, - UI_ID_FAKE_USER = 1 << 8, + UI_ID_MAKE_LOCAL = 1 << 6, + UI_ID_LIB_OVERRIDE_ADD = 1 << 7, + UI_ID_AUTO_NAME = 1 << 8, UI_ID_PIN = 1 << 9, UI_ID_PREVIEWS = 1 << 10, - UI_ID_OVERRIDE = 1 << 11, + UI_ID_LIB_OVERRIDE_REMOVE = 1 << 11, + UI_ID_LIB_OVERRIDE_RESET = 1 << 12, UI_ID_FULL = UI_ID_RENAME | UI_ID_BROWSE | UI_ID_ADD_NEW | UI_ID_OPEN | UI_ID_ALONE | - UI_ID_DELETE | UI_ID_LOCAL, + UI_ID_DELETE | UI_ID_MAKE_LOCAL | UI_ID_LIB_OVERRIDE_ADD | + UI_ID_LIB_OVERRIDE_REMOVE | UI_ID_LIB_OVERRIDE_RESET, }; /** @@ -1652,10 +1669,12 @@ void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN); void UI_but_func_pushed_state_set(uiBut *but, uiButPushedStateFunc func, void *arg); -PointerRNA *UI_but_extra_operator_icon_add(uiBut *but, - const char *opname, - short opcontext, - int icon); +struct uiButExtraOpIcon *UI_but_extra_operator_icon_add(uiBut *but, + const char *opname, + short opcontext, + int icon); +struct wmOperatorType *UI_but_extra_operator_icon_optype_get(struct uiButExtraOpIcon *extra_icon); +PointerRNA *UI_but_extra_operator_icon_opptr_get(struct uiButExtraOpIcon *extra_icon); /* Autocomplete * @@ -1879,6 +1898,7 @@ uiBlock *uiLayoutGetBlock(uiLayout *layout); void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv); void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr); +struct bContextStore *uiLayoutGetContextStore(uiLayout *layout); void uiLayoutContextCopy(uiLayout *layout, struct bContextStore *context); struct wmOperatorType *UI_but_operatortype_get_from_enum_menu(struct uiBut *but, PropertyRNA **r_prop); @@ -1903,7 +1923,7 @@ void uiLayoutSetScaleX(uiLayout *layout, float scale); void uiLayoutSetScaleY(uiLayout *layout, float scale); void uiLayoutSetUnitsX(uiLayout *layout, float unit); void uiLayoutSetUnitsY(uiLayout *layout, float unit); -void uiLayoutSetEmboss(uiLayout *layout, char emboss); +void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss); void uiLayoutSetPropSep(uiLayout *layout, bool is_sep); void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep); int uiLayoutGetLocalDir(const uiLayout *layout); @@ -1922,7 +1942,7 @@ float uiLayoutGetScaleX(uiLayout *layout); float uiLayoutGetScaleY(uiLayout *layout); float uiLayoutGetUnitsX(uiLayout *layout); float uiLayoutGetUnitsY(uiLayout *layout); -int uiLayoutGetEmboss(uiLayout *layout); +eUIEmbossType uiLayoutGetEmboss(uiLayout *layout); bool uiLayoutGetPropSep(uiLayout *layout); bool uiLayoutGetPropDecorate(uiLayout *layout); @@ -1956,6 +1976,7 @@ void uiTemplateID(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *newop, + const char *duplicateop, const char *openop, const char *unlinkop, int filter, @@ -2560,6 +2581,11 @@ struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but, bool is_label); +struct ARegion *UI_tooltip_create_from_button_or_extra_icon(struct bContext *C, + struct ARegion *butregion, + uiBut *but, + uiButExtraOpIcon *extra_icon, + bool is_label); struct ARegion *UI_tooltip_create_from_gizmo(struct bContext *C, struct wmGizmo *gz); void UI_tooltip_free(struct bContext *C, struct bScreen *screen, struct ARegion *region); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 4a02c6b6e88..7713efd1c78 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1167,16 +1167,21 @@ void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_str * \{ */ static bool ui_but_event_operator_string_from_operator(const bContext *C, - uiBut *but, + wmOperatorCallParams *op_call_params, char *buf, const size_t buf_len) { - BLI_assert(but->optype != NULL); + BLI_assert(op_call_params->optype != NULL); bool found = false; - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; - - if (WM_key_event_operator_string( - C, but->optype->idname, but->opcontext, prop, true, buf, buf_len)) { + IDProperty *prop = (op_call_params->opptr) ? op_call_params->opptr->data : NULL; + + if (WM_key_event_operator_string(C, + op_call_params->optype->idname, + op_call_params->opcontext, + prop, + true, + buf, + buf_len)) { found = true; } return found; @@ -1253,15 +1258,22 @@ static bool ui_but_event_operator_string_from_panel(const bContext *C, return found; } -static bool ui_but_event_operator_string(const bContext *C, - uiBut *but, - char *buf, - const size_t buf_len) +static bool ui_but_event_operator_string( + const bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon, char *buf, const size_t buf_len) { bool found = false; + wmOperatorType *extra_icon_optype = UI_but_extra_operator_icon_optype_get(extra_icon); - if (but->optype != NULL) { - found = ui_but_event_operator_string_from_operator(C, but, buf, buf_len); + if (extra_icon_optype) { + found = ui_but_event_operator_string_from_operator(C, extra_icon->optype_params, buf, buf_len); + } + else if (but->optype != NULL) { + found = ui_but_event_operator_string_from_operator( + C, + &(wmOperatorCallParams){ + .optype = but->optype, .opptr = but->opptr, .opcontext = but->opcontext}, + buf, + buf_len); } else if (UI_but_menutype_get(but) != NULL) { found = ui_but_event_operator_string_from_menu(C, but, buf, buf_len); @@ -1564,7 +1576,7 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) continue; } - if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) { + if (ui_but_event_operator_string(C, but, NULL, buf, sizeof(buf))) { ui_but_add_shortcut(but, buf, false); } else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) { @@ -1605,12 +1617,12 @@ typedef enum PredefinedExtraOpIconType { PREDEFINED_EXTRA_OP_ICON_EYEDROPPER, } PredefinedExtraOpIconType; -static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but, - wmOperatorType *optype, - short opcontext, - int icon) +static uiButExtraOpIcon *ui_but_extra_operator_icon_add_ptr(uiBut *but, + wmOperatorType *optype, + short opcontext, + int icon) { - uiButExtraOpIcon *extra_op_icon = MEM_mallocN(sizeof(*extra_op_icon), __func__); + uiButExtraOpIcon *extra_op_icon = MEM_callocN(sizeof(*extra_op_icon), __func__); extra_op_icon->icon = (BIFIconID)icon; extra_op_icon->optype_params = MEM_callocN(sizeof(*extra_op_icon->optype_params), @@ -1625,13 +1637,15 @@ static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but, BLI_addtail(&but->extra_op_icons, extra_op_icon); - return extra_op_icon->optype_params->opptr; + return extra_op_icon; } static void ui_but_extra_operator_icon_free(uiButExtraOpIcon *extra_icon) { - WM_operator_properties_free(extra_icon->optype_params->opptr); - MEM_freeN(extra_icon->optype_params->opptr); + if (extra_icon->optype_params->opptr) { + WM_operator_properties_free(extra_icon->optype_params->opptr); + MEM_freeN(extra_icon->optype_params->opptr); + } MEM_freeN(extra_icon->optype_params); MEM_freeN(extra_icon); } @@ -1644,18 +1658,25 @@ void ui_but_extra_operator_icons_free(uiBut *but) BLI_listbase_clear(&but->extra_op_icons); } -PointerRNA *UI_but_extra_operator_icon_add(uiBut *but, - const char *opname, - short opcontext, - int icon) +uiButExtraOpIcon *UI_but_extra_operator_icon_add(uiBut *but, + const char *opname, + short opcontext, + int icon) { wmOperatorType *optype = WM_operatortype_find(opname, false); - if (optype) { - return ui_but_extra_operator_icon_add_ptr(but, optype, opcontext, icon); - } + BLI_assert(optype); + return ui_but_extra_operator_icon_add_ptr(but, optype, opcontext, icon); +} - return NULL; +PointerRNA *UI_but_extra_operator_icon_opptr_get(uiButExtraOpIcon *extra_icon) +{ + return extra_icon->optype_params->opptr; +} + +wmOperatorType *UI_but_extra_operator_icon_optype_get(uiButExtraOpIcon *extra_icon) +{ + return extra_icon ? extra_icon->optype_params->optype : NULL; } static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but) @@ -3352,7 +3373,7 @@ static void ui_but_free(const bContext *C, uiBut *but) } if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_freeN(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); } ui_but_extra_operator_icons_free(but); @@ -3457,7 +3478,7 @@ void UI_block_region_set(uiBlock *block, ARegion *region) block->oldblock = oldblock; } -uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, char emboss) +uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, eUIEmbossType emboss) { wmWindow *window = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); @@ -3508,7 +3529,7 @@ char UI_block_emboss_get(uiBlock *block) return block->emboss; } -void UI_block_emboss_set(uiBlock *block, char emboss) +void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss) { block->emboss = emboss; } @@ -4552,6 +4573,15 @@ static uiBut *ui_def_but_rna(uiBlock *block, UI_but_disable(but, info); } + if (proptype == PROP_POINTER) { + /* If the button shows an ID, automatically set it as focused in context so operators can + * access it.*/ + const PointerRNA pptr = RNA_property_pointer_get(ptr, prop); + if (pptr.data && RNA_struct_is_ID(pptr.type)) { + but->context = CTX_store_add(&block->contexts, "id", &pptr); + } + } + if (but->flag & UI_BUT_UNDO && (ui_but_is_rna_undo(but) == false)) { but->flag &= ~UI_BUT_UNDO; } @@ -6089,17 +6119,42 @@ void UI_but_drag_set_id(uiBut *but, ID *id) { but->dragtype = WM_DRAG_ID; if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_SAFE_FREE(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; } but->dragpoin = (void *)id; } +void UI_but_drag_set_asset(uiBut *but, + const char *name, + const char *path, + int id_type, + int icon, + struct ImBuf *imb, + float scale) +{ + wmDragAsset *asset_drag = MEM_mallocN(sizeof(*asset_drag), "wmDragAsset"); + + BLI_strncpy(asset_drag->name, name, sizeof(asset_drag->name)); + asset_drag->path = path; + asset_drag->id_type = id_type; + + but->dragtype = WM_DRAG_ASSET; + ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */ + if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { + WM_drag_data_free(but->dragtype, but->dragpoin); + } + but->dragpoin = asset_drag; + but->dragflag |= UI_BUT_DRAGPOIN_FREE; + but->imb = imb; + but->imb_scale = scale; +} + void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr) { but->dragtype = WM_DRAG_RNA; if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_SAFE_FREE(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; } but->dragpoin = (void *)ptr; @@ -6109,7 +6164,7 @@ void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free) { but->dragtype = WM_DRAG_PATH; if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_SAFE_FREE(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; } but->dragpoin = (void *)path; @@ -6122,7 +6177,7 @@ void UI_but_drag_set_name(uiBut *but, const char *name) { but->dragtype = WM_DRAG_NAME; if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_SAFE_FREE(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; } but->dragpoin = (void *)name; @@ -6140,7 +6195,7 @@ void UI_but_drag_set_image( but->dragtype = WM_DRAG_PATH; ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */ if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_SAFE_FREE(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; } but->dragpoin = (void *)path; @@ -6784,7 +6839,7 @@ void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN) but->hold_argN = argN; } -void UI_but_string_info_get(bContext *C, uiBut *but, ...) +void UI_but_string_info_get(bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon, ...) { va_list args; uiStringInfo *si; @@ -6793,13 +6848,19 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) int totitems; bool free_items = false; - va_start(args, but); + wmOperatorType *extra_icon_optype = UI_but_extra_operator_icon_optype_get(extra_icon); + wmOperatorType *optype = extra_icon ? extra_icon_optype : but->optype; + + /* Don't query RNA data when the extra-icon overrides the button. */ + PropertyRNA *rnaprop = extra_icon ? NULL : but->rnaprop; + + va_start(args, extra_icon); while ((si = (uiStringInfo *)va_arg(args, void *))) { uiStringInfoType type = si->type; char *tmp = NULL; if (type == BUT_GET_LABEL) { - if (but->str && but->str[0]) { + if (but->str && but->str[0] && !extra_icon) { const char *str_sep; size_t str_len; @@ -6829,16 +6890,16 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) } if (type == BUT_GET_RNAPROP_IDENTIFIER) { - if (but->rnaprop) { - tmp = BLI_strdup(RNA_property_identifier(but->rnaprop)); + if (rnaprop) { + tmp = BLI_strdup(RNA_property_identifier(rnaprop)); } } else if (type == BUT_GET_RNASTRUCT_IDENTIFIER) { - if (but->rnaprop && but->rnapoin.data) { + if (rnaprop && but->rnapoin.data) { tmp = BLI_strdup(RNA_struct_identifier(but->rnapoin.type)); } - else if (but->optype) { - tmp = BLI_strdup(but->optype->idname); + else if (optype) { + tmp = BLI_strdup(optype->idname); } else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) { MenuType *mt = UI_but_menutype_get(but); @@ -6854,23 +6915,25 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) } } else if (ELEM(type, BUT_GET_RNA_LABEL, BUT_GET_RNA_TIP)) { - if (but->rnaprop) { + if (rnaprop) { if (type == BUT_GET_RNA_LABEL) { - tmp = BLI_strdup(RNA_property_ui_name(but->rnaprop)); + tmp = BLI_strdup(RNA_property_ui_name(rnaprop)); } else { - const char *t = RNA_property_ui_description(but->rnaprop); + const char *t = RNA_property_ui_description(rnaprop); if (t && t[0]) { tmp = BLI_strdup(t); } } } - else if (but->optype) { + else if (optype) { + PointerRNA *opptr = extra_icon_optype ? UI_but_extra_operator_icon_opptr_get(extra_icon) : + but->opptr; if (type == BUT_GET_RNA_LABEL) { - tmp = BLI_strdup(WM_operatortype_name(but->optype, but->opptr)); + tmp = BLI_strdup(WM_operatortype_name(optype, opptr)); } else { - tmp = WM_operatortype_description(C, but->optype, but->opptr); + tmp = WM_operatortype_description(C, optype, opptr); } } else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)) { @@ -6922,11 +6985,11 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) } else if (type == BUT_GET_RNA_LABEL_CONTEXT) { const char *_tmp = BLT_I18NCONTEXT_DEFAULT; - if (but->rnaprop) { - _tmp = RNA_property_translation_context(but->rnaprop); + if (rnaprop) { + _tmp = RNA_property_translation_context(rnaprop); } - else if (but->optype) { - _tmp = RNA_struct_translation_context(but->optype->srna); + else if (optype) { + _tmp = RNA_struct_translation_context(optype->srna); } else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) { MenuType *mt = UI_but_menutype_get(but); @@ -6945,16 +7008,16 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) int value = 0; /* get the enum property... */ - if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM) { + if (rnaprop && RNA_property_type(rnaprop) == PROP_ENUM) { /* enum property */ ptr = &but->rnapoin; - prop = but->rnaprop; + prop = rnaprop; value = (ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_TAB)) ? (int)but->hardmax : (int)ui_but_value_get(but); } - else if (but->optype) { - PointerRNA *opptr = UI_but_operator_ptr_get(but); - wmOperatorType *ot = but->optype; + else if (optype) { + PointerRNA *opptr = extra_icon_optype ? UI_but_extra_operator_icon_opptr_get(extra_icon) : + UI_but_operator_ptr_get(but); /* so the context is passed to itemf functions */ WM_operator_properties_sanitize(opptr, false); @@ -6964,11 +7027,11 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) * operator menus in the Anim Editors will show tooltips for the different * operations instead of the meaningless generic operator tooltip */ - if (ot->prop && RNA_property_type(ot->prop) == PROP_ENUM) { - if (RNA_struct_contains_property(opptr, ot->prop)) { + if (optype->prop && RNA_property_type(optype->prop) == PROP_ENUM) { + if (RNA_struct_contains_property(opptr, optype->prop)) { ptr = opptr; - prop = ot->prop; - value = RNA_property_enum_get(opptr, ot->prop); + prop = optype->prop; + value = RNA_property_enum_get(opptr, optype->prop); } } } @@ -7001,7 +7064,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) else if (type == BUT_GET_OP_KEYMAP) { if (!ui_block_is_menu(but->block)) { char buf[128]; - if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) { + if (ui_but_event_operator_string(C, but, extra_icon, buf, sizeof(buf))) { tmp = BLI_strdup(buf); } } diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 39b405a02b8..fd3b00eec31 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -38,6 +38,7 @@ #include "BKE_idprop.h" #include "BKE_screen.h" +#include "ED_asset.h" #include "ED_keyframing.h" #include "ED_screen.h" @@ -503,17 +504,23 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) uiPopupMenu *pup; uiLayout *layout; + bContextStore *previous_ctx = CTX_store_get(C); { uiStringInfo label = {BUT_GET_LABEL, NULL}; /* highly unlikely getting the label ever fails */ - UI_but_string_info_get(C, but, &label, NULL); + UI_but_string_info_get(C, but, NULL, &label, NULL); pup = UI_popup_menu_begin(C, label.strinfo ? label.strinfo : "", ICON_NONE); layout = UI_popup_menu_layout(pup); if (label.strinfo) { MEM_freeN(label.strinfo); } + + if (but->context) { + uiLayoutContextCopy(layout, but->context); + CTX_store_set(C, uiLayoutGetContextStore(layout)); + } uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); } @@ -946,6 +953,22 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) } } + /* If the button reprents an id, it can set the "id" context pointer. */ + if (ED_asset_can_make_single_from_context(C)) { + ID *id = CTX_data_pointer_get_type(C, "id", &RNA_ID).data; + + /* Gray out items depending on if data-block is an asset. Preferably this could be done via + * operator poll, but that doesn't work since the operator also works with "selected_ids", + * which isn't cheap to check. */ + uiLayout *sub = uiLayoutColumn(layout, true); + uiLayoutSetEnabled(sub, !id->asset_data); + uiItemO(sub, NULL, ICON_NONE, "ASSET_OT_mark"); + sub = uiLayoutColumn(layout, true); + uiLayoutSetEnabled(sub, id->asset_data); + uiItemO(sub, NULL, ICON_NONE, "ASSET_OT_clear"); + uiItemS(layout); + } + /* Pointer properties and string properties with * prop_search support jumping to target object/bone. */ if (but->rnapoin.data && but->rnaprop) { @@ -1210,6 +1233,10 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) UI_menutype_draw(C, mt, uiLayoutColumn(layout, false)); } + if (but->context) { + CTX_store_set(C, previous_ctx); + } + return UI_popup_menu_end_or_cancel(C, pup); } diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c index 7f735a0e789..f2899fc0098 100644 --- a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c +++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c @@ -34,6 +34,7 @@ #include "BLT_translation.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_space_types.h" #include "BKE_context.h" diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index f914ccd7497..790c2cd5313 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -334,6 +334,7 @@ typedef struct uiHandleButtonData { int retval; /* booleans (could be made into flags) */ bool cancel, escapecancel; + bool skip_undo_push; bool applied, applied_interactive; bool changed_cursor; wmTimer *flashtimer; @@ -626,7 +627,11 @@ static bool ui_rna_is_userdef(PointerRNA *ptr, PropertyRNA *prop) if (base == NULL) { base = ptr->type; } - if (ELEM(base, &RNA_AddonPreferences, &RNA_KeyConfigPreferences, &RNA_KeyMapItem)) { + if (ELEM(base, + &RNA_AddonPreferences, + &RNA_KeyConfigPreferences, + &RNA_KeyMapItem, + &RNA_UserAssetLibrary)) { tag = true; } } @@ -816,7 +821,9 @@ static void ui_apply_but_func(bContext *C, uiBut *but) /* typically call ui_apply_but_undo(), ui_apply_but_autokey() */ static void ui_apply_but_undo(uiBut *but) { - if (but->flag & UI_BUT_UNDO) { + const bool force_skip_undo = (but->active && but->active->skip_undo_push); + + if (but->flag & UI_BUT_UNDO && !force_skip_undo) { const char *str = NULL; size_t str_len_clip = SIZE_MAX - 1; bool skip_undo = false; @@ -1349,6 +1356,9 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl if (mbut_state == NULL) { /* Highly unlikely. */ printf("%s: Can't find button\n", __func__); + /* While this avoids crashing, multi-button dragging will fail, + * which is still a bug from the user perspective. See T83651. */ + continue; } void *active_back; @@ -1984,6 +1994,8 @@ static bool ui_but_drag_init(bContext *C, else { wmDrag *drag = WM_event_start_drag( C, but->icon, but->dragtype, but->dragpoin, ui_but_value_get(but), WM_DRAG_NOP); + /* wmDrag has ownership over dragpoin now, stop messing with it. */ + but->dragpoin = NULL; if (but->imb) { WM_event_drag_image(drag, @@ -2256,10 +2268,11 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB ListBase *drags = event->customdata; /* drop event type has listbase customdata by default */ LISTBASE_FOREACH (wmDrag *, wmd, drags) { + /* TODO asset dropping. */ if (wmd->type == WM_DRAG_ID) { /* align these types with UI_but_active_drop_name */ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { - ID *id = WM_drag_ID(wmd, 0); + ID *id = WM_drag_get_local_ID(wmd, 0); button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); @@ -2856,7 +2869,8 @@ void ui_but_active_string_clear_and_exit(bContext *C, uiBut *but) but->active->str[0] = 0; ui_apply_but_TEX(C, but, but->active); - button_activate_state(C, but, BUTTON_STATE_EXIT); + /* use onfree event so undo is handled by caller and apply is already done above */ + button_activate_exit((bContext *)C, but, but->active, false, true); } static void ui_textedit_string_ensure_max_length(uiBut *but, uiHandleButtonData *data, int maxlen) @@ -4001,16 +4015,38 @@ static void ui_numedit_apply(bContext *C, uiBlock *block, uiBut *but, uiHandleBu ED_region_tag_redraw(data->region); } -static void ui_but_extra_operator_icon_apply(bContext *C, uiBut *but, uiButExtraOpIcon *op_icon) +static void ui_but_extra_operator_icon_apply_func(uiBut *but, uiButExtraOpIcon *op_icon) { - if (but->active->interactive) { - ui_apply_but(C, but->block, but, but->active, true); + if (ui_afterfunc_check(but->block, but)) { + uiAfterFunc *after = ui_afterfunc_new(); + + after->optype = op_icon->optype_params->optype; + after->opcontext = op_icon->optype_params->opcontext; + after->opptr = op_icon->optype_params->opptr; + + if (but->context) { + after->context = CTX_store_copy(but->context); + } + + /* Ownership moved, don't let the UI code free it. */ + op_icon->optype_params->opptr = NULL; } +} + +static void ui_but_extra_operator_icon_apply(bContext *C, + uiBut *but, + uiHandleButtonData *data, + uiButExtraOpIcon *op_icon) +{ 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); + ui_apply_but(C, but->block, but, data, true); + + data->postbut = but; + data->posttype = BUTTON_ACTIVATE_OVER; + /* Leave undo up to the operator. */ + data->skip_undo_push = true; + + ui_but_extra_operator_icon_apply_func(but, op_icon); /* Force recreation of extra operator icons (pseudo update). */ ui_but_extra_operator_icons_free(but); @@ -4209,7 +4245,7 @@ static bool ui_do_but_extra_operator_icon(bContext *C, ED_region_tag_redraw(data->region); button_tooltip_timer_reset(C, but); - ui_but_extra_operator_icon_apply(C, but, op_icon); + ui_but_extra_operator_icon_apply(C, but, data, op_icon); /* Note: 'but', 'data' may now be freed, don't access. */ return true; @@ -5851,7 +5887,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) { ColorPicker *cpicker = but->custom_data; float hsv_static[3] = {0.0f}; - float *hsv = cpicker ? cpicker->color_data : hsv_static; + float *hsv = cpicker ? cpicker->hsv_perceptual : hsv_static; float col[3]; ui_but_v3_get(but, col); @@ -6079,7 +6115,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, { const uiButHSVCube *hsv_but = (uiButHSVCube *)but; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; float rgb[3]; float x, y; float mx_fl, my_fl; @@ -6097,7 +6133,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, #endif ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); + ui_scene_linear_to_perceptual_space(but, rgb); ui_rgb_to_color_picker_HSVCUBE_compat_v(hsv_but, rgb, hsv); @@ -6110,7 +6146,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, /* calculate original hsv again */ copy_v3_v3(rgb, data->origvec); - ui_scene_linear_to_color_picker_space(but, rgb); + ui_scene_linear_to_perceptual_space(but, rgb); copy_v3_v3(hsvo, hsv); @@ -6173,7 +6209,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, } ui_color_picker_to_rgb_HSVCUBE_v(hsv_but, hsv, rgb); - ui_color_picker_to_scene_linear_space(but, rgb); + ui_perceptual_to_scene_linear_space(but, rgb); /* clamp because with color conversion we can exceed range T34295. */ if (hsv_but->gradient_type == UI_GRAD_V_ALT) { @@ -6196,13 +6232,13 @@ static void ui_ndofedit_but_HSVCUBE(uiButHSVCube *hsv_but, const bool shift) { ColorPicker *cpicker = hsv_but->but.custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; const float hsv_v_max = max_ff(hsv[2], hsv_but->but.softmax); float rgb[3]; const float sensitivity = (shift ? 0.15f : 0.3f) * ndof->dt; ui_but_v3_get(&hsv_but->but, rgb); - ui_scene_linear_to_color_picker_space(&hsv_but->but, rgb); + ui_scene_linear_to_perceptual_space(&hsv_but->but, rgb); ui_rgb_to_color_picker_HSVCUBE_compat_v(hsv_but, rgb, hsv); switch (hsv_but->gradient_type) { @@ -6251,7 +6287,7 @@ static void ui_ndofedit_but_HSVCUBE(uiButHSVCube *hsv_but, hsv_clamp_v(hsv, hsv_v_max); ui_color_picker_to_rgb_HSVCUBE_v(hsv_but, hsv, rgb); - ui_color_picker_to_scene_linear_space(&hsv_but->but, rgb); + ui_perceptual_to_scene_linear_space(&hsv_but->but, rgb); copy_v3_v3(data->vec, rgb); ui_but_v3_set(&hsv_but->but, data->vec); @@ -6308,7 +6344,7 @@ static int ui_do_but_HSVCUBE( float rgb[3], def_hsv[3]; float def[4]; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def); ui_rgb_to_color_picker_HSVCUBE_v(hsv_but, def, def_hsv); @@ -6364,7 +6400,7 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, { const bool changed = true; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; float mx_fl, my_fl; ui_mouse_scale_warp(data, mx, my, &mx_fl, &my_fl, shift); @@ -6390,8 +6426,8 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, float rgb[3]; ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + ui_scene_linear_to_perceptual_space(but, rgb); + ui_color_picker_rgb_to_hsv_compat(rgb, hsv); /* exception, when using color wheel in 'locked' value state: * allow choosing a hue for black values, by giving a tiny increment */ @@ -6418,8 +6454,8 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, /* calculate original hsv again */ copy_v3_v3(hsvo, hsv); copy_v3_v3(rgbo, data->origvec); - ui_scene_linear_to_color_picker_space(but, rgbo); - ui_rgb_to_color_picker_compat_v(rgbo, hsvo); + ui_scene_linear_to_perceptual_space(but, rgbo); + ui_color_picker_rgb_to_hsv_compat(rgbo, hsvo); /* and original position */ ui_hsvcircle_pos_from_vals(cpicker, &rect, hsvo, &xpos, &ypos); @@ -6438,7 +6474,7 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, ui_color_snap_hue(snap, &hsv[0]); } - ui_color_picker_to_rgb_v(hsv, rgb); + ui_color_picker_hsv_to_rgb(hsv, rgb); if ((cpicker->use_luminosity_lock)) { if (!is_zero_v3(rgb)) { @@ -6446,7 +6482,7 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, } } - ui_color_picker_to_scene_linear_space(but, rgb); + ui_perceptual_to_scene_linear_space(but, rgb); ui_but_v3_set(but, rgb); data->draglastx = mx; @@ -6463,14 +6499,14 @@ static void ui_ndofedit_but_HSVCIRCLE(uiBut *but, const bool shift) { ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; float rgb[3]; float phi, r /*, sqr */ /* UNUSED */, v[2]; const float sensitivity = (shift ? 0.06f : 0.3f) * ndof->dt; ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + ui_scene_linear_to_perceptual_space(but, rgb); + ui_color_picker_rgb_to_hsv_compat(rgb, hsv); /* Convert current color on hue/sat disc to circular coordinates phi, r */ phi = fmodf(hsv[0] + 0.25f, 1.0f) * -2.0f * (float)M_PI; @@ -6520,7 +6556,7 @@ static void ui_ndofedit_but_HSVCIRCLE(uiBut *but, hsv_clamp_v(hsv, FLT_MAX); - ui_color_picker_to_rgb_v(hsv, data->vec); + ui_color_picker_hsv_to_rgb(hsv, data->vec); if (cpicker->use_luminosity_lock) { if (!is_zero_v3(data->vec)) { @@ -6528,7 +6564,7 @@ static void ui_ndofedit_but_HSVCIRCLE(uiBut *but, } } - ui_color_picker_to_scene_linear_space(but, data->vec); + ui_perceptual_to_scene_linear_space(but, data->vec); ui_but_v3_set(but, data->vec); } #endif /* WITH_INPUT_NDOF */ @@ -6537,7 +6573,7 @@ static int ui_do_but_HSVCIRCLE( bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; int mx = event->x; int my = event->y; ui_window_to_block(data->region, block, &mx, &my); @@ -6584,10 +6620,10 @@ static int ui_do_but_HSVCIRCLE( def = MEM_callocN(sizeof(float) * len, "reset_defaults - float"); RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def); - ui_color_picker_to_rgb_v(def, def_hsv); + ui_color_picker_hsv_to_rgb(def, def_hsv); ui_but_v3_get(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + ui_color_picker_rgb_to_hsv_compat(rgb, hsv); def_hsv[0] = hsv[0]; def_hsv[2] = hsv[2]; @@ -7844,7 +7880,10 @@ static ARegion *ui_but_tooltip_init( uiBut *but = UI_region_active_but_get(region); *r_exit_on_event = false; if (but) { - return UI_tooltip_create_from_button(C, region, but, is_label); + uiButExtraOpIcon *extra_icon = ui_but_extra_operator_icon_mouse_over_get( + but, but->active, CTX_wm_window(C)->eventstate); + + return UI_tooltip_create_from_button_or_extra_icon(C, region, but, extra_icon, is_label); } return NULL; } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 90f5172f6ec..899f4a6ddb1 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -100,11 +100,12 @@ typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha); #define ICON_TYPE_COLOR_TEXTURE 1 #define ICON_TYPE_MONO_TEXTURE 2 #define ICON_TYPE_BUFFER 3 -#define ICON_TYPE_VECTOR 4 -#define ICON_TYPE_GEOM 5 -#define ICON_TYPE_EVENT 6 /* draw keymap entries using custom renderer. */ -#define ICON_TYPE_GPLAYER 7 -#define ICON_TYPE_BLANK 8 +#define ICON_TYPE_IMBUF 4 +#define ICON_TYPE_VECTOR 5 +#define ICON_TYPE_GEOM 6 +#define ICON_TYPE_EVENT 7 /* draw keymap entries using custom renderer. */ +#define ICON_TYPE_GPLAYER 8 +#define ICON_TYPE_BLANK 9 typedef struct DrawInfo { int type; @@ -1147,6 +1148,9 @@ static DrawInfo *icon_create_drawinfo(Icon *icon) if (ELEM(icon_data_type, ICON_DATA_ID, ICON_DATA_PREVIEW)) { di->type = ICON_TYPE_PREVIEW; } + else if (icon_data_type == ICON_DATA_IMBUF) { + di->type = ICON_TYPE_IMBUF; + } else if (icon_data_type == ICON_DATA_GEOM) { di->type = ICON_TYPE_GEOM; } @@ -1262,7 +1266,7 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size) else if (!prv_img->rect[size]) { prv_img->w[size] = render_size; prv_img->h[size] = render_size; - prv_img->flag[size] |= PRV_CHANGED; + prv_img->flag[size] |= (PRV_CHANGED | PRV_UNFINISHED); prv_img->changed_timestamp[size] = 0; prv_img->rect[size] = MEM_callocN(render_size * render_size * sizeof(uint), "prv_rect"); } @@ -1384,8 +1388,12 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi } } -/* only called when icon has changed */ -/* only call with valid pointer from UI_icon_draw */ +/** + * * Only call with valid pointer from UI_icon_draw. + * * Only called when icon has changed. + * + * Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored. + */ static void icon_set_image(const bContext *C, Scene *scene, ID *id, @@ -1408,7 +1416,7 @@ static void icon_set_image(const bContext *C, const bool delay = prv_img->rect[size] != NULL; icon_create_rect(prv_img, size); - if (use_job) { + if (use_job && (!id || BKE_previewimg_id_supports_jobs(id))) { /* Job (background) version */ ED_preview_icon_job( C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size], delay); @@ -1790,7 +1798,14 @@ static void icon_draw_size(float x, /* We need to flush widget base first to ensure correct ordering. */ UI_widgetbase_draw_cache_flush(); - if (di->type == ICON_TYPE_VECTOR) { + if (di->type == ICON_TYPE_IMBUF) { + ImBuf *ibuf = icon->obj; + + GPU_blend(GPU_BLEND_ALPHA_PREMULT); + icon_draw_rect(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate); + GPU_blend(GPU_BLEND_ALPHA); + } + else if (di->type == ICON_TYPE_VECTOR) { /* vector icons use the uiBlock transformation, they are not drawn * with untransformed coordinates like the other icons */ di->data.vector.func((int)x, (int)y, w, h, 1.0f); @@ -1937,6 +1952,9 @@ static void ui_id_preview_image_render_size( } } +/** + * Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored. + */ void UI_icon_render_id(const bContext *C, Scene *scene, ID *id, const bool big, const bool use_job) { PreviewImage *pi = BKE_previewimg_id_ensure(id); @@ -1964,12 +1982,7 @@ static void ui_id_icon_render(const bContext *C, ID *id, bool use_jobs) } for (enum eIconSizes i = 0; i < NUM_ICON_SIZES; i++) { - /* check if rect needs to be created; changed - * only set by dynamic icons */ - if (((pi->flag[i] & PRV_CHANGED) || !pi->rect[i])) { - icon_set_image(C, NULL, id, pi, i, use_jobs); - pi->flag[i] &= ~PRV_CHANGED; - } + ui_id_preview_image_render_size(C, NULL, id, pi, i, use_jobs); } } @@ -2186,6 +2199,9 @@ int UI_icon_from_library(const ID *id) if (ID_IS_OVERRIDE_LIBRARY(id)) { return ICON_LIBRARY_DATA_OVERRIDE; } + if (ID_IS_ASSET(id)) { + return ICON_MAT_SPHERE_SKY; + } return ICON_NONE; } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 5c7cad4c8d5..c005b456b6a 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -220,8 +220,8 @@ struct uiBut { const char *disabled_info; BIFIconID icon; - /** emboss: UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied from the #uiBlock.emboss */ - char emboss; + /** Copied from the #uiBlock.emboss */ + eUIEmbossType emboss; /** direction in a pie menu, used for collision detection (RadialDirection) */ signed char pie_dir; /** could be made into a single flag */ @@ -378,11 +378,20 @@ typedef struct uiButExtraOpIcon { typedef struct ColorPicker { struct ColorPicker *next, *prev; - /** Color data, may be HSV or HSL. */ - float color_data[3]; - /** Initial color data (detect changes). */ - float color_data_init[3]; + + /** Color in HSV or HSL, in color picking color space. Used for HSV cube, + * circle and slider widgets. The color picking space is perceptually + * linear for intuitive editing. */ + float hsv_perceptual[3]; + /** Initial color data (to detect changes). */ + float hsv_perceptual_init[3]; bool is_init; + + /** HSV or HSL color in scene linear color space value used for number + * buttons. This is scene linear so that there is a clear correspondence + * to the scene linear RGB values. */ + float hsv_scene_linear[3]; + /** Cubic saturation for the color wheel. */ bool use_color_cubic; bool use_color_lock; @@ -493,8 +502,8 @@ struct uiBlock { char direction; /** UI_BLOCK_THEME_STYLE_* */ char theme_style; - /** UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied to #uiBut.emboss */ - char emboss; + /** Copied to #uiBut.emboss */ + eUIEmbossType emboss; bool auto_open; char _pad[5]; double auto_open_last; @@ -734,15 +743,14 @@ struct uiPopupBlockHandle { /* exposed as public API in UI_interface.h */ /* interface_region_color_picker.c */ -void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]); -void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3]); -void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3]); -void ui_color_picker_to_rgb(float r_cp0, float r_cp1, float r_cp2, float *r, float *g, float *b); +void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3]); +void ui_color_picker_rgb_to_hsv(const float rgb[3], float r_cp[3]); +void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3]); bool ui_but_is_color_gamma(uiBut *but); -void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3]); -void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3]); +void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3]); +void ui_perceptual_to_scene_linear_space(uiBut *but, float rgb[3]); uiBlock *ui_block_func_COLOR(struct bContext *C, uiPopupBlockHandle *handle, void *arg_but); ColorPicker *ui_block_colorpicker_create(struct uiBlock *block); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 0403287125c..3ea7a5f5973 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -172,7 +172,7 @@ struct uiLayout { /** For layouts inside gridflow, they and their items shall never have a fixed maximal size. */ bool variable_size; char alignment; - char emboss; + eUIEmbossType emboss; /** for fixed width or height to avoid UI size changes */ float units[2]; }; @@ -651,7 +651,7 @@ static void ui_item_array(uiLayout *layout, uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y); } else { - /* even if 'expand' is fale, expanding anyway */ + /* Even if 'expand' is false, we expand anyway. */ /* layout for known array subtypes */ char str[3] = {'\0'}; @@ -1189,7 +1189,7 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout, const int w = ui_text_icon_width(layout, name, icon, 0); - const int prev_emboss = layout->emboss; + const eUIEmbossType prev_emboss = layout->emboss; if (flag & UI_ITEM_R_NO_BG) { layout->emboss = UI_EMBOSS_NONE; } @@ -2120,7 +2120,7 @@ void uiItemFullR(uiLayout *layout, int w, h; ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, compact, &w, &h); - const int prev_emboss = layout->emboss; + const eUIEmbossType prev_emboss = layout->emboss; if (no_bg) { layout->emboss = UI_EMBOSS_NONE; } @@ -3457,8 +3457,6 @@ static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void void uiItemMenuEnumR_prop( uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *name, int icon) { - MenuItemLevel *lvl; - if (!name) { name = RNA_property_ui_name(prop); } @@ -3466,7 +3464,7 @@ void uiItemMenuEnumR_prop( icon = ICON_BLANK1; } - lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel"); + MenuItemLevel *lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel"); lvl->rnapoin = *ptr; BLI_strncpy(lvl->propname, RNA_property_identifier(prop), sizeof(lvl->propname)); lvl->opcontext = layout->root->opcontext; @@ -3550,15 +3548,15 @@ static int ui_litem_min_width(int itemw) static void ui_litem_layout_row(uiLayout *litem) { uiItem *last_free_item = NULL; - int x, y, w, tot, totw, neww, newtotw, itemw, minw, itemh, offset; - int fixedw, freew, fixedx, freex, flag = 0, lastw = 0; + int x, neww, newtotw, itemw, minw, itemh, offset; + int freew, fixedx, freex, flag = 0, lastw = 0; float extra_pixel; /* x = litem->x; */ /* UNUSED */ - y = litem->y; - w = litem->w; - totw = 0; - tot = 0; + int y = litem->y; + int w = litem->w; + int totw = 0; + int tot = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { ui_item_size(item, &itemw, &itemh); @@ -3573,7 +3571,7 @@ static void ui_litem_layout_row(uiLayout *litem) if (w != 0) { w -= (tot - 1) * litem->space; } - fixedw = 0; + int fixedw = 0; /* keep clamping items to fixed minimum size until all are done */ do { @@ -3724,12 +3722,11 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box) static void ui_litem_layout_column(uiLayout *litem, bool is_box, bool is_menu) { - int itemw, itemh, x, y; - - x = litem->x; - y = litem->y; + int x = litem->x; + int y = litem->y; LISTBASE_FOREACH (uiItem *, item, &litem->items) { + int itemw, itemh; ui_item_size(item, &itemw, &itemh); y -= itemh; @@ -3753,15 +3750,13 @@ static void ui_litem_layout_column(uiLayout *litem, bool is_box, bool is_menu) * stores a float vector in unit circle */ static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum) { - RadialDirection dir; - if (itemnum >= PIE_MAX_ITEMS) { itemnum %= PIE_MAX_ITEMS; printf("Warning: Pie menus with more than %i items are currently unsupported\n", PIE_MAX_ITEMS); } - dir = ui_radial_dir_order[itemnum]; + RadialDirection dir = ui_radial_dir_order[itemnum]; ui_but_pie_dir(dir, vec); return dir; @@ -3789,7 +3784,7 @@ static bool ui_item_is_radial_drawable(uiButtonItem *bitem) static void ui_litem_layout_radial(uiLayout *litem) { - int itemh, itemw, x, y; + int itemh, itemw; int itemnum = 0; int totitems = 0; @@ -3800,8 +3795,8 @@ static void ui_litem_layout_radial(uiLayout *litem) const int pie_radius = U.pie_menu_radius * UI_DPI_FAC; - x = litem->x; - y = litem->y; + int x = litem->x; + int y = litem->y; int minx = x, miny = y, maxx = x, maxy = y; @@ -3921,16 +3916,14 @@ static void ui_litem_layout_box(uiLayout *litem) { uiLayoutItemBx *box = (uiLayoutItemBx *)litem; const uiStyle *style = litem->root->style; - uiBut *but; - int w, h; int boxspace = style->boxspace; if (litem->root->type == UI_LAYOUT_HEADER) { boxspace = 0; } - w = litem->w; - h = litem->h; + int w = litem->w; + int h = litem->h; litem->x += boxspace; litem->y -= boxspace; @@ -3955,7 +3948,7 @@ static void ui_litem_layout_box(uiLayout *litem) } /* roundbox around the sublayout */ - but = box->roundbox; + uiBut *but = box->roundbox; but->rect.xmin = litem->x; but->rect.ymin = litem->y; but->rect.xmax = litem->x + litem->w; @@ -3967,12 +3960,11 @@ static void ui_litem_estimate_column_flow(uiLayout *litem) { const uiStyle *style = litem->root->style; uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem; - int col, x, y, emh, emy, miny, itemw, itemh, maxw = 0; - int toth, totitem; + int itemw, itemh, maxw = 0; /* compute max needed width and total height */ - toth = 0; - totitem = 0; + int toth = 0; + int totitem = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { ui_item_size(item, &itemw, &itemh); maxw = MAX2(maxw, itemw); @@ -3995,16 +3987,16 @@ static void ui_litem_estimate_column_flow(uiLayout *litem) } /* compute sizes */ - x = 0; - y = 0; - emy = 0; - miny = 0; + int x = 0; + int y = 0; + int emy = 0; + int miny = 0; maxw = 0; - emh = toth / flow->totcol; + int emh = toth / flow->totcol; /* create column per column */ - col = 0; + int col = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { ui_item_size(item, &itemw, &itemh); @@ -4031,12 +4023,11 @@ static void ui_litem_layout_column_flow(uiLayout *litem) { const uiStyle *style = litem->root->style; uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem; - int col, x, y, w, emh, emy, miny, itemw, itemh; - int toth, totitem; + int col, emh, itemw, itemh; /* compute max needed width and total height */ - toth = 0; - totitem = 0; + int toth = 0; + int totitem = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { ui_item_size(item, &itemw, &itemh); toth += itemh; @@ -4044,12 +4035,12 @@ static void ui_litem_layout_column_flow(uiLayout *litem) } /* compute sizes */ - x = litem->x; - y = litem->y; - emy = 0; - miny = 0; + int x = litem->x; + int y = litem->y; + int emy = 0; + int miny = 0; - w = litem->w - (flow->totcol - 1) * style->columnspace; + int w = litem->w - (flow->totcol - 1) * style->columnspace; emh = toth / flow->totcol; /* create column per column */ @@ -4457,14 +4448,13 @@ static void ui_litem_layout_grid_flow(uiLayout *litem) /* free layout */ static void ui_litem_estimate_absolute(uiLayout *litem) { - int itemx, itemy, itemw, itemh, minx, miny; - - minx = 1e6; - miny = 1e6; + int minx = 1e6; + int miny = 1e6; litem->w = 0; litem->h = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { + int itemx, itemy, itemw, itemh; ui_item_offset(item, &itemx, &itemy); ui_item_size(item, &itemw, &itemh); @@ -4482,12 +4472,12 @@ static void ui_litem_estimate_absolute(uiLayout *litem) static void ui_litem_layout_absolute(uiLayout *litem) { float scalex = 1.0f, scaley = 1.0f; - int x, y, newx, newy, itemx, itemy, itemh, itemw, minx, miny, totw, toth; + int x, y, newx, newy, itemx, itemy, itemh, itemw; - minx = 1e6; - miny = 1e6; - totw = 0; - toth = 0; + int minx = 1e6; + int miny = 1e6; + int totw = 0; + int toth = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { ui_item_offset(item, &itemx, &itemy); @@ -4548,24 +4538,24 @@ static void ui_litem_estimate_split(uiLayout *litem) static void ui_litem_layout_split(uiLayout *litem) { uiLayoutItemSplit *split = (uiLayoutItemSplit *)litem; - float percentage, extra_pixel = 0.0f; + float extra_pixel = 0.0f; const int tot = BLI_listbase_count(&litem->items); - int itemh, x, y, w, colw = 0; if (tot == 0) { return; } - x = litem->x; - y = litem->y; + int x = litem->x; + int y = litem->y; - percentage = (split->percentage == 0.0f) ? 1.0f / (float)tot : split->percentage; + float percentage = (split->percentage == 0.0f) ? 1.0f / (float)tot : split->percentage; - w = (litem->w - (tot - 1) * litem->space); - colw = w * percentage; + int w = (litem->w - (tot - 1) * litem->space); + int colw = w * percentage; colw = MAX2(colw, 0); LISTBASE_FOREACH (uiItem *, item, &litem->items) { + int itemh; ui_item_size(item, NULL, &itemh); ui_item_position(item, x, y - itemh, colw, itemh); @@ -4590,12 +4580,11 @@ static void ui_litem_layout_split(uiLayout *litem) /* overlap layout */ static void ui_litem_estimate_overlap(uiLayout *litem) { - int itemw, itemh; - litem->w = 0; litem->h = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { + int itemw, itemh; ui_item_size(item, &itemw, &itemh); litem->w = MAX2(itemw, litem->w); @@ -4605,12 +4594,12 @@ static void ui_litem_estimate_overlap(uiLayout *litem) static void ui_litem_layout_overlap(uiLayout *litem) { - int itemw, itemh, x, y; - x = litem->x; - y = litem->y; + int x = litem->x; + int y = litem->y; LISTBASE_FOREACH (uiItem *, item, &litem->items) { + int itemw, itemh; ui_item_size(item, &itemw, &itemh); ui_item_position(item, x, y - itemh, litem->w, itemh); @@ -4657,9 +4646,7 @@ static void ui_layout_heading_set(uiLayout *layout, const char *heading) /* layout create functions */ uiLayout *uiLayoutRow(uiLayout *layout, bool align) { - uiLayout *litem; - - litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow"); + uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow"); ui_litem_init_from_parent(litem, layout, align); litem->item.type = ITEM_LAYOUT_ROW; @@ -4682,9 +4669,7 @@ uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *headi uiLayout *uiLayoutColumn(uiLayout *layout, bool align) { - uiLayout *litem; - - litem = MEM_callocN(sizeof(uiLayout), "uiLayoutColumn"); + uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutColumn"); ui_litem_init_from_parent(litem, layout, align); litem->item.type = ITEM_LAYOUT_COLUMN; @@ -4710,9 +4695,7 @@ uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *he uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align) { - uiLayoutItemFlow *flow; - - flow = MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow"); + uiLayoutItemFlow *flow = MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow"); ui_litem_init_from_parent(&flow->litem, layout, align); flow->litem.item.type = ITEM_LAYOUT_COLUMN_FLOW; @@ -4731,9 +4714,7 @@ uiLayout *uiLayoutGridFlow(uiLayout *layout, bool even_rows, bool align) { - uiLayoutItemGridFlow *flow; - - flow = MEM_callocN(sizeof(uiLayoutItemGridFlow), __func__); + uiLayoutItemGridFlow *flow = MEM_callocN(sizeof(uiLayoutItemGridFlow), __func__); flow->litem.item.type = ITEM_LAYOUT_GRID_FLOW; ui_litem_init_from_parent(&flow->litem, layout, align); @@ -4750,9 +4731,7 @@ uiLayout *uiLayoutGridFlow(uiLayout *layout, static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type) { - uiLayoutItemBx *box; - - box = MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx"); + uiLayoutItemBx *box = MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx"); ui_litem_init_from_parent(&box->litem, layout, false); box->litem.item.type = ITEM_LAYOUT_BOX; @@ -4767,8 +4746,6 @@ static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type) uiLayout *uiLayoutRadial(uiLayout *layout) { - uiLayout *litem; - /* radial layouts are only valid for radial menus */ if (layout->root->type != UI_LAYOUT_PIEMENU) { return ui_item_local_sublayout(layout, layout, 0); @@ -4776,14 +4753,14 @@ uiLayout *uiLayoutRadial(uiLayout *layout) /* only one radial wheel per root layout is allowed, so check and return that, if it exists */ LISTBASE_FOREACH (uiItem *, item, &layout->root->layout->items) { - litem = (uiLayout *)item; + uiLayout *litem = (uiLayout *)item; if (litem->item.type == ITEM_LAYOUT_RADIAL) { UI_block_layout_set_current(layout->root->block, litem); return litem; } } - litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRadial"); + uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRadial"); ui_litem_init_from_parent(litem, layout, false); litem->item.type = ITEM_LAYOUT_RADIAL; @@ -4838,9 +4815,7 @@ uiLayout *uiLayoutListBox(uiLayout *layout, uiLayout *uiLayoutAbsolute(uiLayout *layout, bool align) { - uiLayout *litem; - - litem = MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute"); + uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute"); ui_litem_init_from_parent(litem, layout, align); litem->item.type = ITEM_LAYOUT_ABSOLUTE; @@ -4852,9 +4827,7 @@ uiLayout *uiLayoutAbsolute(uiLayout *layout, bool align) uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout) { - uiBlock *block; - - block = uiLayoutGetBlock(layout); + uiBlock *block = uiLayoutGetBlock(layout); uiLayoutAbsolute(layout, false); return block; @@ -4862,9 +4835,7 @@ uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout) uiLayout *uiLayoutOverlap(uiLayout *layout) { - uiLayout *litem; - - litem = MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap"); + uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap"); ui_litem_init_from_parent(litem, layout, false); litem->item.type = ITEM_LAYOUT_OVERLAP; @@ -4876,9 +4847,7 @@ uiLayout *uiLayoutOverlap(uiLayout *layout) uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, bool align) { - uiLayoutItemSplit *split; - - split = MEM_callocN(sizeof(uiLayoutItemSplit), "uiLayoutItemSplit"); + uiLayoutItemSplit *split = MEM_callocN(sizeof(uiLayoutItemSplit), "uiLayoutItemSplit"); ui_litem_init_from_parent(&split->litem, layout, align); split->litem.item.type = ITEM_LAYOUT_SPLIT; @@ -4945,7 +4914,7 @@ void uiLayoutSetUnitsY(uiLayout *layout, float unit) layout->units[1] = unit; } -void uiLayoutSetEmboss(uiLayout *layout, char emboss) +void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss) { layout->emboss = emboss; } @@ -5030,7 +4999,7 @@ float uiLayoutGetUnitsY(uiLayout *layout) return layout->units[1]; } -int uiLayoutGetEmboss(uiLayout *layout) +eUIEmbossType uiLayoutGetEmboss(uiLayout *layout) { if (layout->emboss == UI_EMBOSS_UNDEFINED) { return layout->root->block->emboss; @@ -5290,12 +5259,9 @@ static void ui_item_estimate(uiItem *item) static void ui_item_align(uiLayout *litem, short nr) { - uiButtonItem *bitem; - uiLayoutItemBx *box; - LISTBASE_FOREACH_BACKWARD (uiItem *, item, &litem->items) { if (item->type == ITEM_BUTTON) { - bitem = (uiButtonItem *)item; + uiButtonItem *bitem = (uiButtonItem *)item; #ifndef USE_UIBUT_SPATIAL_ALIGN if (ui_but_can_align(bitem->but)) #endif @@ -5312,7 +5278,7 @@ static void ui_item_align(uiLayout *litem, short nr) /* pass */ } else if (item->type == ITEM_LAYOUT_BOX) { - box = (uiLayoutItemBx *)item; + uiLayoutItemBx *box = (uiLayoutItemBx *)item; if (!box->roundbox->alignnr) { box->roundbox->alignnr = nr; } @@ -5325,11 +5291,9 @@ static void ui_item_align(uiLayout *litem, short nr) static void ui_item_flag(uiLayout *litem, int flag) { - uiButtonItem *bitem; - LISTBASE_FOREACH_BACKWARD (uiItem *, item, &litem->items) { if (item->type == ITEM_BUTTON) { - bitem = (uiButtonItem *)item; + uiButtonItem *bitem = (uiButtonItem *)item; bitem->but->flag |= flag; } else { @@ -5465,17 +5429,14 @@ uiLayout *UI_block_layout(uiBlock *block, int padding, const uiStyle *style) { - uiLayout *layout; - uiLayoutRoot *root; - - root = MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot"); + uiLayoutRoot *root = MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot"); root->type = type; root->style = style; root->block = block; root->padding = padding; root->opcontext = WM_OP_INVOKE_REGION_WIN; - layout = MEM_callocN(sizeof(uiLayout), "uiLayout"); + uiLayout *layout = MEM_callocN(sizeof(uiLayout), "uiLayout"); layout->item.type = (type == UI_LAYOUT_VERT_BAR) ? ITEM_LAYOUT_COLUMN : ITEM_LAYOUT_ROOT; /* Only used when 'UI_ITEM_PROP_SEP' is set. */ @@ -5485,8 +5446,8 @@ uiLayout *UI_block_layout(uiBlock *block, layout->y = y; layout->root = root; layout->space = style->templatespace; - layout->active = 1; - layout->enabled = 1; + layout->active = true; + layout->enabled = true; layout->context = NULL; layout->emboss = UI_EMBOSS_UNDEFINED; @@ -5529,9 +5490,7 @@ void UI_block_layout_set_current(uiBlock *block, uiLayout *layout) void ui_layout_add_but(uiLayout *layout, uiBut *but) { - uiButtonItem *bitem; - - bitem = MEM_callocN(sizeof(uiButtonItem), "uiButtonItem"); + uiButtonItem *bitem = MEM_callocN(sizeof(uiButtonItem), "uiButtonItem"); bitem->item.type = ITEM_BUTTON; bitem->but = but; @@ -5663,6 +5622,11 @@ void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *p layout->context = CTX_store_add(&block->contexts, name, ptr); } +bContextStore *uiLayoutGetContextStore(uiLayout *layout) +{ + return layout->context; +} + void uiLayoutContextCopy(uiLayout *layout, bContextStore *context) { uiBlock *block = layout->root->block; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 0d1e2802242..2995cff8ed5 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1223,7 +1223,7 @@ typedef struct uiEditSourceStore { typedef struct uiEditSourceButStore { char py_dbg_fn[FILE_MAX]; - int py_dbg_ln; + int py_dbg_line_number; } uiEditSourceButStore; /* should only ever be set while the edit source operator is running */ @@ -1276,21 +1276,21 @@ void UI_editsource_active_but_test(uiBut *but) struct uiEditSourceButStore *but_store = MEM_callocN(sizeof(uiEditSourceButStore), __func__); const char *fn; - int lineno = -1; + int line_number = -1; # if 0 printf("comparing buttons: '%s' == '%s'\n", but->drawstr, ui_editsource_info->but_orig.drawstr); # endif - PyC_FileAndNum_Safe(&fn, &lineno); + PyC_FileAndNum_Safe(&fn, &line_number); - if (lineno != -1) { + if (line_number != -1) { BLI_strncpy(but_store->py_dbg_fn, fn, sizeof(but_store->py_dbg_fn)); - but_store->py_dbg_ln = lineno; + but_store->py_dbg_line_number = line_number; } else { but_store->py_dbg_fn[0] = '\0'; - but_store->py_dbg_ln = -1; + but_store->py_dbg_line_number = -1; } BLI_ghash_insert(ui_editsource_info->hash, but, but_store); @@ -1375,8 +1375,8 @@ static int editsource_exec(bContext *C, wmOperator *op) } if (but_store) { - if (but_store->py_dbg_ln != -1) { - ret = editsource_text_edit(C, op, but_store->py_dbg_fn, but_store->py_dbg_ln); + if (but_store->py_dbg_line_number != -1) { + ret = editsource_text_edit(C, op, but_store->py_dbg_fn, but_store->py_dbg_line_number); } else { BKE_report( @@ -1521,6 +1521,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op) UI_but_string_info_get(C, but, + NULL, &but_label, &rna_label, &enum_label, diff --git a/source/blender/editors/interface/interface_region_color_picker.c b/source/blender/editors/interface/interface_region_color_picker.c index f9a9e7182d2..82028d4e595 100644 --- a/source/blender/editors/interface/interface_region_color_picker.c +++ b/source/blender/editors/interface/interface_region_color_picker.c @@ -77,8 +77,10 @@ static void ui_color_picker_rgb_round(float rgb[3]) } } -void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]) +void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3]) { + /* Convert RGB to HSV, remaining as compatible as possible with the existing + * r_hsv value (for example when value goes to zero, preserve the hue). */ switch (U.color_picker_type) { case USER_CP_CIRCLE_HSL: rgb_to_hsl_compat_v(rgb, r_cp); @@ -89,7 +91,7 @@ void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]) } } -void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3]) +void ui_color_picker_rgb_to_hsv(const float rgb[3], float r_cp[3]) { switch (U.color_picker_type) { case USER_CP_CIRCLE_HSL: @@ -101,7 +103,7 @@ void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3]) } } -void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3]) +void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3]) { switch (U.color_picker_type) { case USER_CP_CIRCLE_HSL: @@ -113,18 +115,6 @@ void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3]) } } -void ui_color_picker_to_rgb(float r_cp0, float r_cp1, float r_cp2, float *r, float *g, float *b) -{ - switch (U.color_picker_type) { - case USER_CP_CIRCLE_HSL: - hsl_to_rgb(r_cp0, r_cp1, r_cp2, r, g, b); - break; - default: - hsv_to_rgb(r_cp0, r_cp1, r_cp2, r, g, b); - break; - } -} - /* Returns true if the button is for a color with gamma baked in, * or if it's a color picker for such a button. */ bool ui_but_is_color_gamma(uiBut *but) @@ -138,7 +128,7 @@ bool ui_but_is_color_gamma(uiBut *but) return but->block->is_color_gamma_picker; } -void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3]) +void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3]) { /* Map to color picking space for HSV values and HSV cube/circle, * assuming it is more perceptually linear than the scene linear @@ -149,7 +139,7 @@ void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3]) } } -void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3]) +void ui_perceptual_to_scene_linear_space(uiBut *but, float rgb[3]) { if (!ui_but_is_color_gamma(but)) { IMB_colormanagement_color_picking_to_scene_linear_v3(rgb); @@ -163,16 +153,46 @@ void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3]) /** \name Color Picker * \{ */ +static void ui_color_picker_update_hsv(ColorPicker *cpicker, + uiBut *from_but, + const float rgb_scene_linear[3]) +{ + /* Convert from RGB to HSV in scene linear space color for number editing. */ + if (cpicker->is_init == false) { + ui_color_picker_rgb_to_hsv(rgb_scene_linear, cpicker->hsv_scene_linear); + } + else { + ui_color_picker_rgb_to_hsv_compat(rgb_scene_linear, cpicker->hsv_scene_linear); + } + + /* Convert from RGB to HSV in perceptually linear space for picker widgets. */ + float rgb_perceptual[3]; + copy_v3_v3(rgb_perceptual, rgb_scene_linear); + if (from_but) { + ui_scene_linear_to_perceptual_space(from_but, rgb_perceptual); + } + + if (cpicker->is_init == false) { + ui_color_picker_rgb_to_hsv(rgb_perceptual, cpicker->hsv_perceptual); + copy_v3_v3(cpicker->hsv_perceptual_init, cpicker->hsv_perceptual); + } + else { + ui_color_picker_rgb_to_hsv_compat(rgb_perceptual, cpicker->hsv_perceptual); + } + + cpicker->is_init = true; +} + /* for picker, while editing hsv */ void ui_but_hsv_set(uiBut *but) { - float col[3]; + float rgb_perceptual[3]; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv_perceptual = cpicker->hsv_perceptual; - ui_color_picker_to_rgb_v(hsv, col); + ui_color_picker_hsv_to_rgb(hsv_perceptual, rgb_perceptual); - ui_but_v3_set(but, col); + ui_but_v3_set(but, rgb_perceptual); } /* Updates all buttons who share the same color picker as the one passed @@ -180,17 +200,9 @@ void ui_but_hsv_set(uiBut *but) static void ui_update_color_picker_buts_rgb(uiBut *from_but, uiBlock *block, ColorPicker *cpicker, - const float rgb[3]) + const float rgb_scene_linear[3]) { - float *hsv = cpicker->color_data; - - /* Convert from RGB to HSV in perceptually linear space. */ - float tmp[3]; - copy_v3_v3(tmp, rgb); - if (from_but) { - ui_scene_linear_to_color_picker_space(from_but, tmp); - } - ui_rgb_to_color_picker_compat_v(tmp, hsv); + ui_color_picker_update_hsv(cpicker, from_but, rgb_scene_linear); /* this updates button strings, * is hackish... but button pointers are on stack of caller function */ @@ -200,7 +212,7 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but, } if (bt->rnaprop) { - ui_but_v3_set(bt, rgb); + ui_but_v3_set(bt, rgb_scene_linear); /* original button that created the color picker already does undo * push, so disable it on RNA buttons in the color picker block */ @@ -213,7 +225,7 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but, /* Hex code is assumed to be in sRGB space * (coming from other applications, web, etc) */ - copy_v3_v3(rgb_hex, rgb); + copy_v3_v3(rgb_hex, rgb_scene_linear); if (from_but && !ui_but_is_color_gamma(from_but)) { IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex); ui_color_picker_rgb_round(rgb_hex); @@ -226,25 +238,25 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but, } else if (bt->str[1] == ' ') { if (bt->str[0] == 'R') { - ui_but_value_set(bt, rgb[0]); + ui_but_value_set(bt, rgb_scene_linear[0]); } else if (bt->str[0] == 'G') { - ui_but_value_set(bt, rgb[1]); + ui_but_value_set(bt, rgb_scene_linear[1]); } else if (bt->str[0] == 'B') { - ui_but_value_set(bt, rgb[2]); + ui_but_value_set(bt, rgb_scene_linear[2]); } else if (bt->str[0] == 'H') { - ui_but_value_set(bt, hsv[0]); + ui_but_value_set(bt, cpicker->hsv_scene_linear[0]); } else if (bt->str[0] == 'S') { - ui_but_value_set(bt, hsv[1]); + ui_but_value_set(bt, cpicker->hsv_scene_linear[1]); } else if (bt->str[0] == 'V') { - ui_but_value_set(bt, hsv[2]); + ui_but_value_set(bt, cpicker->hsv_scene_linear[2]); } else if (bt->str[0] == 'L') { - ui_but_value_set(bt, hsv[2]); + ui_but_value_set(bt, cpicker->hsv_scene_linear[2]); } } @@ -252,17 +264,17 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but, } } -static void ui_colorpicker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) +static void ui_colorpicker_rgba_update_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) { uiBut *but = (uiBut *)bt1; uiPopupBlockHandle *popup = but->block->handle; PropertyRNA *prop = but->rnaprop; PointerRNA ptr = but->rnapoin; - float rgb[4]; + float rgb_scene_linear[4]; if (prop) { - RNA_property_float_get_array(&ptr, prop, rgb); - ui_update_color_picker_buts_rgb(but, but->block, but->custom_data, rgb); + RNA_property_float_get_array(&ptr, prop, rgb_scene_linear); + ui_update_color_picker_buts_rgb(but, but->block, but->custom_data, rgb_scene_linear); } if (popup) { @@ -270,20 +282,15 @@ static void ui_colorpicker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(a } } -static void ui_color_wheel_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) +static void ui_colorpicker_hsv_update_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) { uiBut *but = (uiBut *)bt1; uiPopupBlockHandle *popup = but->block->handle; - float rgb[3]; + float rgb_scene_linear[3]; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; - ui_color_picker_to_rgb_v(hsv, rgb); - - /* hsv is saved in perceptually linear space so convert back */ - ui_color_picker_to_scene_linear_space(but, rgb); - - ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb); + ui_color_picker_hsv_to_rgb(cpicker->hsv_scene_linear, rgb_scene_linear); + ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb_scene_linear); if (popup) { popup->menuretval = UI_RETURN_UPDATE; @@ -321,7 +328,7 @@ static void ui_popup_close_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) if (popup) { ColorPicker *cpicker = but->custom_data; BLI_assert(cpicker->is_init); - popup->menuretval = (equals_v3v3(cpicker->color_data, cpicker->color_data_init) ? + popup->menuretval = (equals_v3v3(cpicker->hsv_perceptual, cpicker->hsv_perceptual_init) ? UI_RETURN_CANCEL : UI_RETURN_OK); } @@ -331,12 +338,12 @@ static void ui_colorpicker_hide_reveal(uiBlock *block, enum ePickerType colormod { /* tag buttons */ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) { - if ((bt->func == ui_colorpicker_rna_cb) && (bt->type == UI_BTYPE_NUM_SLIDER) && + if ((bt->func == ui_colorpicker_rgba_update_cb) && (bt->type == UI_BTYPE_NUM_SLIDER) && (bt->rnaindex != 3)) { /* RGB sliders (color circle and alpha are always shown) */ SET_FLAG_FROM_TEST(bt->flag, (colormode != PICKER_TYPE_RGB), UI_HIDDEN); } - else if (bt->func == ui_color_wheel_rna_cb) { + else if (bt->func == ui_colorpicker_hsv_update_cb) { /* HSV sliders */ SET_FLAG_FROM_TEST(bt->flag, (colormode != PICKER_TYPE_HSV), UI_HIDDEN); } @@ -386,7 +393,7 @@ static void ui_colorpicker_circle(uiBlock *block, 0.0, 0, TIP_("Color")); - UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL); + UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL); bt->custom_data = cpicker; /* value */ @@ -408,7 +415,7 @@ static void ui_colorpicker_circle(uiBlock *block, 0, "Lightness"); hsv_but->gradient_type = UI_GRAD_L_ALT; - UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL); + UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL); } else { hsv_but = (uiButHSVCube *)uiDefButR_prop(block, @@ -428,7 +435,7 @@ static void ui_colorpicker_circle(uiBlock *block, 0, TIP_("Value")); hsv_but->gradient_type = UI_GRAD_V_ALT; - UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL); + UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL); } hsv_but->but.custom_data = cpicker; } @@ -461,7 +468,7 @@ static void ui_colorpicker_square(uiBlock *block, 0, TIP_("Color")); hsv_but->gradient_type = type; - UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL); + UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL); hsv_but->but.custom_data = cpicker; /* value */ @@ -482,12 +489,15 @@ static void ui_colorpicker_square(uiBlock *block, 0, TIP_("Value")); hsv_but->gradient_type = type + 3; - UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL); + UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL); hsv_but->but.custom_data = cpicker; } /* a HS circle, V slider, rgb/hsv/hex sliders */ -static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], bool show_picker) +static void ui_block_colorpicker(uiBlock *block, + uiBut *from_but, + float rgba_scene_linear[4], + bool show_picker) { /* ePickerType */ static char colormode = 1; @@ -497,7 +507,6 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], float softmin, softmax, hardmin, hardmax, step, precision; int yco; ColorPicker *cpicker = ui_block_colorpicker_create(block); - float *hsv = cpicker->color_data; PointerRNA *ptr = &from_but->rnapoin; PropertyRNA *prop = from_but->rnaprop; @@ -505,20 +514,13 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], butwidth = width - 1.5f * UI_UNIT_X; /* sneaky way to check for alpha */ - rgba[3] = FLT_MAX; + rgba_scene_linear[3] = FLT_MAX; RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision); RNA_property_float_range(ptr, prop, &hardmin, &hardmax); - RNA_property_float_get_array(ptr, prop, rgba); + RNA_property_float_get_array(ptr, prop, rgba_scene_linear); - float rgb_perceptual[3]; - copy_v3_v3(rgb_perceptual, rgba); - ui_scene_linear_to_color_picker_space(from_but, rgb_perceptual); - ui_rgb_to_color_picker_v(rgb_perceptual, hsv); - if (cpicker->is_init == false) { - copy_v3_v3(cpicker->color_data_init, cpicker->color_data); - cpicker->is_init = true; - } + ui_color_picker_update_hsv(cpicker, from_but, rgba_scene_linear); /* when the softmax isn't defined in the RNA, * using very large numbers causes sRGB/linear round trip to fail. */ @@ -639,7 +641,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], 0, 3, TIP_("Red")); - UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL); + UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL); bt->custom_data = cpicker; bt = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, @@ -657,7 +659,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], 0, 3, TIP_("Green")); - UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL); + UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL); bt->custom_data = cpicker; bt = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, @@ -675,7 +677,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], 0, 3, TIP_("Blue")); - UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL); + UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL); bt->custom_data = cpicker; /* Could use: @@ -693,14 +695,14 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], yco, butwidth, UI_UNIT_Y, - hsv, + cpicker->hsv_scene_linear, 0.0, 1.0, 10, 3, TIP_("Hue")); UI_but_flag_disable(bt, UI_BUT_UNDO); - UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv); + UI_but_func_set(bt, ui_colorpicker_hsv_update_cb, bt, NULL); bt->custom_data = cpicker; bt = uiDefButF(block, UI_BTYPE_NUM_SLIDER, @@ -710,14 +712,14 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, - hsv + 1, + cpicker->hsv_scene_linear + 1, 0.0, 1.0, 10, 3, TIP_("Saturation")); UI_but_flag_disable(bt, UI_BUT_UNDO); - UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv); + UI_but_func_set(bt, ui_colorpicker_hsv_update_cb, bt, NULL); bt->custom_data = cpicker; if (U.color_picker_type == USER_CP_CIRCLE_HSL) { bt = uiDefButF(block, @@ -728,7 +730,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, - hsv + 2, + cpicker->hsv_scene_linear + 2, 0.0, 1.0, 10, @@ -744,7 +746,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, - hsv + 2, + cpicker->hsv_scene_linear + 2, 0.0, softmax, 10, @@ -754,12 +756,12 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], UI_but_flag_disable(bt, UI_BUT_UNDO); bt->hardmax = hardmax; /* not common but rgb may be over 1.0 */ - UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv); + UI_but_func_set(bt, ui_colorpicker_hsv_update_cb, bt, NULL); bt->custom_data = cpicker; UI_block_align_end(block); - if (rgba[3] != FLT_MAX) { + if (rgba_scene_linear[3] != FLT_MAX) { bt = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, 0, @@ -776,18 +778,18 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], 0, 3, TIP_("Alpha")); - UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL); + UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL); bt->custom_data = cpicker; } else { - rgba[3] = 1.0f; + rgba_scene_linear[3] = 1.0f; } /* Hex color is in sRGB space. */ float rgb_hex[3]; uchar rgb_hex_uchar[3]; - copy_v3_v3(rgb_hex, rgba); + copy_v3_v3(rgb_hex, rgba_scene_linear); if (!ui_but_is_color_gamma(from_but)) { IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex); @@ -850,21 +852,22 @@ static int ui_colorpicker_small_wheel_cb(const bContext *UNUSED(C), LISTBASE_FOREACH (uiBut *, but, &block->buttons) { if (but->type == UI_BTYPE_HSVCUBE && but->active == NULL) { uiPopupBlockHandle *popup = block->handle; - float rgb[3]; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv_perceptual = cpicker->hsv_perceptual; - ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + float rgb_perceptual[3]; + ui_but_v3_get(but, rgb_perceptual); + ui_scene_linear_to_perceptual_space(but, rgb_perceptual); + ui_color_picker_rgb_to_hsv_compat(rgb_perceptual, hsv_perceptual); - hsv[2] = clamp_f(hsv[2] + add, 0.0f, 1.0f); + hsv_perceptual[2] = clamp_f(hsv_perceptual[2] + add, 0.0f, 1.0f); - ui_color_picker_to_rgb_v(hsv, rgb); - ui_color_picker_to_scene_linear_space(but, rgb); - ui_but_v3_set(but, rgb); + float rgb_scene_linear[3]; + ui_color_picker_hsv_to_rgb(hsv_perceptual, rgb_scene_linear); + ui_perceptual_to_scene_linear_space(but, rgb_scene_linear); + ui_but_v3_set(but, rgb_scene_linear); - ui_update_color_picker_buts_rgb(but, block, cpicker, rgb); + ui_update_color_picker_buts_rgb(but, block, cpicker, rgb_scene_linear); if (popup) { popup->menuretval = UI_RETURN_UPDATE; } diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 12f3ba609f0..89515608c5b 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -534,7 +534,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is { uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL}; - UI_but_string_info_get(C, but, &op_keymap, NULL); + UI_but_string_info_get(C, but, NULL, &op_keymap, NULL); shortcut = op_keymap.strinfo; } @@ -764,7 +764,9 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is return data; } -static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) +static uiTooltipData *ui_tooltip_data_from_button(bContext *C, + uiBut *but, + uiButExtraOpIcon *extra_icon) { uiStringInfo but_label = {BUT_GET_LABEL, NULL}; uiStringInfo but_tip = {BUT_GET_TIP, NULL}; @@ -777,20 +779,29 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) char buf[512]; + wmOperatorType *extra_icon_optype = UI_but_extra_operator_icon_optype_get(extra_icon); + wmOperatorType *optype = extra_icon ? extra_icon_optype : but->optype; + /* create tooltip data */ uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); - UI_but_string_info_get(C, - but, - &but_label, - &but_tip, - &enum_label, - &enum_tip, - &op_keymap, - &prop_keymap, - &rna_struct, - &rna_prop, - NULL); + if (extra_icon) { + UI_but_string_info_get(C, but, extra_icon, &but_label, &but_tip, &op_keymap, NULL); + } + else { + UI_but_string_info_get(C, + but, + NULL, + &but_label, + &but_tip, + &enum_label, + &enum_tip, + &op_keymap, + &prop_keymap, + &rna_struct, + &rna_prop, + NULL); + } /* Tip Label (only for buttons not already showing the label). * Check prefix instead of comparing because the button may include the shortcut. */ @@ -923,15 +934,16 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) } } } - else if (but->optype) { - PointerRNA *opptr; - char *str; - opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */ + else if (optype) { + PointerRNA *opptr = extra_icon_optype ? + UI_but_extra_operator_icon_opptr_get(extra_icon) : + UI_but_operator_ptr_get( + but); /* allocated when needed, the button owns it */ /* so the context is passed to fieldf functions (some py fieldf functions use it) */ WM_operator_properties_sanitize(opptr, false); - str = ui_tooltip_text_python_from_op(C, but->optype, opptr); + char *str = ui_tooltip_text_python_from_op(C, optype, opptr); /* operator info */ if (U.flag & USER_TOOLTIPS_PYTHON) { @@ -958,7 +970,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) disabled_msg = CTX_wm_operator_poll_msg_get(C); } /* alternatively, buttons can store some reasoning too */ - else if (but->disabled_info) { + if (!disabled_msg && but->disabled_info) { disabled_msg = TIP_(but->disabled_info); } @@ -1398,11 +1410,8 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, /** \name ToolTip Public API * \{ */ -/** - * \param is_label: When true, show a small tip that only shows the name, - * otherwise show the full tooltip. - */ -ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label) +ARegion *UI_tooltip_create_from_button_or_extra_icon( + bContext *C, ARegion *butregion, uiBut *but, uiButExtraOpIcon *extra_icon, bool is_label) { wmWindow *win = CTX_wm_window(C); /* aspect values that shrink text are likely unreadable */ @@ -1419,7 +1428,7 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b } if (data == NULL) { - data = ui_tooltip_data_from_button(C, but); + data = ui_tooltip_data_from_button(C, but, extra_icon); } if (data == NULL) { @@ -1457,6 +1466,15 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b return region; } +/** + * \param is_label: When true, show a small tip that only shows the name, + * otherwise show the full tooltip. + */ +ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label) +{ + return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, NULL, is_label); +} + ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz) { wmWindow *win = CTX_wm_window(C); diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index c3d528ad5c5..a37fb0dfde1 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -206,8 +206,12 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs, BLF_disable(fs->uifont_id, font_flag); - *r_xofs = xofs; - *r_yofs = yofs; + if (r_xofs) { + *r_xofs = xofs; + } + if (r_yofs) { + *r_yofs = yofs; + } } void UI_fontstyle_draw(const uiFontStyle *fs, diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 43ead511cfe..404ae0df6a1 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -102,9 +102,16 @@ // #define USE_OP_RESET_BUT /* defines for templateID/TemplateSearch */ -#define TEMPLATE_SEARCH_TEXTBUT_WIDTH (UI_UNIT_X * 6) +#define TEMPLATE_SEARCH_TEXTBUT_WIDTH (UI_UNIT_X * 8) #define TEMPLATE_SEARCH_TEXTBUT_HEIGHT UI_UNIT_Y +/* Add "Make Single User" button to templateID. Users can just manually duplicate an ID, it's + * unclear what the use-case of this specific button is. So for now disabling it, we can bring it + * back or remove it later. + * - Julian + */ +//#define USE_TEMPLATE_ID_MAKE_SINGLE_USER + void UI_template_fix_linking(void) { } @@ -308,6 +315,12 @@ typedef struct TemplateID { ListBase *idlb; short idcode; + + const char *new_op; + const char *duplicate_op; + const char *unlink_op; + const char *open_op; + short filter; int prv_rows, prv_cols; bool preview; @@ -564,80 +577,64 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) memset(&idptr, 0, sizeof(idptr)); RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); - - if (id && CTX_wm_window(C)->eventstate->shift) { - /* only way to force-remove data (on save) */ - id_us_clear_real(id); - id_fake_user_clear(id); - id->us = 0; - undo_push_label = "Delete Data-Block"; - } - break; - case UI_ID_FAKE_USER: + case UI_ID_MAKE_LOCAL: if (id) { - if (id->flag & LIB_FAKEUSER) { - id_us_plus(id); - } - else { - id_us_min(id); + Main *bmain = CTX_data_main(C); + if (BKE_lib_id_make_local(bmain, id, false, 0)) { + BKE_main_id_clear_newpoins(bmain); + + /* reassign to get get proper updates/notifiers */ + idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); + undo_push_label = "Make Local"; } - undo_push_label = "Fake User"; - } - else { - return; } break; - case UI_ID_LOCAL: - if (id) { + case UI_ID_LIB_OVERRIDE_ADD: + if (id && ID_IS_OVERRIDABLE_LIBRARY(id)) { Main *bmain = CTX_data_main(C); - if (CTX_wm_window(C)->eventstate->shift) { - if (ID_IS_OVERRIDABLE_LIBRARY(id)) { - /* Only remap that specific ID usage to overriding local data-block. */ - ID *override_id = BKE_lib_override_library_create_from_id(bmain, id, false); - if (override_id != NULL) { - BKE_main_id_clear_newpoins(bmain); - - if (GS(override_id->name) == ID_OB) { - Scene *scene = CTX_data_scene(C); - if (!BKE_collection_has_object_recursive(scene->master_collection, - (Object *)override_id)) { - BKE_collection_object_add_from( - bmain, scene, (Object *)id, (Object *)override_id); - } - } - - /* Assign new pointer, takes care of updates/notifiers */ - RNA_id_pointer_create(override_id, &idptr); + /* Only remap that specific ID usage to overriding local data-block. */ + ID *override_id = BKE_lib_override_library_create_from_id(bmain, id, false); + if (override_id != NULL) { + BKE_main_id_clear_newpoins(bmain); + + if (GS(override_id->name) == ID_OB) { + Scene *scene = CTX_data_scene(C); + if (!BKE_collection_has_object_recursive(scene->master_collection, + (Object *)override_id)) { + BKE_collection_object_add_from(bmain, scene, (Object *)id, (Object *)override_id); } - undo_push_label = "Make Library Override"; } - } - else { - if (BKE_lib_id_make_local(bmain, id, false, 0)) { - BKE_main_id_clear_newpoins(bmain); - /* reassign to get get proper updates/notifiers */ - idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); - undo_push_label = "Make Local"; - } - } - if (undo_push_label != NULL) { - RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); - RNA_property_update(C, &template_ui->ptr, template_ui->prop); + /* Assign new pointer, takes care of updates/notifiers */ + RNA_id_pointer_create(override_id, &idptr); } + /* reassign to get get proper updates/notifiers */ + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); + undo_push_label = "Make Library Override"; } break; - case UI_ID_OVERRIDE: + case UI_ID_LIB_OVERRIDE_RESET: + if (id && ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + Main *bmain = CTX_data_main(C); + BKE_lib_override_library_id_reset(bmain, id); + undo_push_label = "Reset Library Override"; + } + break; + case UI_ID_LIB_OVERRIDE_REMOVE: if (id && ID_IS_OVERRIDE_LIBRARY(id)) { BKE_lib_override_library_free(&id->override_library, true); /* reassign to get get proper updates/notifiers */ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); - undo_push_label = "Override Data-Block"; + undo_push_label = "Remove Library Override"; } break; +#ifdef USE_TEMPLATE_ID_MAKE_SINGLE_USER case UI_ID_ALONE: if (id) { const bool do_scene_obj = ((GS(id->name) == ID_OB) && @@ -659,6 +656,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) undo_push_label = "Make Single User"; } break; +#endif #if 0 case UI_ID_AUTO_NAME: break; @@ -772,17 +770,221 @@ static const char *template_id_context(StructRNA *type) # define template_id_context(type) 0 #endif -static uiBut *template_id_def_new_but(uiBlock *block, - const ID *id, - const TemplateID *template_ui, - StructRNA *type, - const char *const newop, - const bool editable, - const bool id_open, - const bool use_tab_but, - int but_height) -{ +static void template_id_linked_operation_button( + uiBlock *block, Main *bmain, ID *id, TemplateID *template_ui, int operation) +{ + BLI_assert(ELEM(operation, UI_ID_MAKE_LOCAL, UI_ID_LIB_OVERRIDE_ADD)); + + const char *label = (operation == UI_ID_MAKE_LOCAL) ? + CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Local") : + CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Library Override"); + const char *tip = (operation == UI_ID_MAKE_LOCAL) ? + N_("Make library linked data-block local to this file") : + N_("Create a local override of this library linked data-block"); + BIFIconID icon = (operation == UI_ID_MAKE_LOCAL) ? ICON_BLANK1 : ICON_LIBRARY_DATA_OVERRIDE; + + uiBut *but = uiDefIconTextBut(block, + UI_BTYPE_BUT, + 0, + icon, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, label), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_(tip)); + + bool disabled = false; + + if (!ID_IS_LINKED(id)) { + disabled = true; + but->disabled_info = TIP_("Data-block is not linked"); + } + else if (id->tag & LIB_TAG_INDIRECT) { + disabled = true; + but->disabled_info = TIP_("Indirect library data-block, cannot change"); + } + else if (!BKE_lib_id_make_local(bmain, id, true /* test */, 0)) { + disabled = true; + but->disabled_info = TIP_("Data-blocks of this type cannot be made local"); + } + else if (!RNA_property_editable_info( + &template_ui->ptr, template_ui->prop, &but->disabled_info)) { + disabled = true; + } + + if (disabled) { + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + else { + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(operation)); + } +} + +static void template_id_library_overridden_button(uiBlock *block, + ID *id, + TemplateID *template_ui, + int operation) +{ + BLI_assert(ELEM(operation, UI_ID_LIB_OVERRIDE_RESET, UI_ID_LIB_OVERRIDE_REMOVE) && + ID_IS_OVERRIDE_LIBRARY(id)); + + if (operation == UI_ID_LIB_OVERRIDE_RESET && ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + uiBut *but = uiDefIconTextBut( + block, + UI_BTYPE_BUT, + 0, + ICON_BLANK1, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset Library Override"), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Reset the local override to the state of " + "the overridden data-block")); + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + but->disabled_info = TIP_("Data-block is a virtual, not a real override"); + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + else { + UI_but_funcN_set(but, + template_id_cb, + MEM_dupallocN(template_ui), + POINTER_FROM_INT(UI_ID_LIB_OVERRIDE_RESET)); + } + } + else if (operation == UI_ID_LIB_OVERRIDE_REMOVE) { + uiBut *but = uiDefIconTextBut( + block, + UI_BTYPE_BUT, + 0, + ICON_BLANK1, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Local"), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Remove library override and make the library linked data-block " + "fully local to this file")); + UI_but_funcN_set(but, + template_id_cb, + MEM_dupallocN(template_ui), + POINTER_FROM_INT(UI_ID_LIB_OVERRIDE_REMOVE)); + } +} + +#ifdef USE_TEMPLATE_ID_MAKE_SINGLE_USER +static uiBut *template_id_make_single_user_button(uiBlock *block, ID *id, TemplateID *template_ui) +{ + uiBut *but = uiDefIconTextBut( + block, + UI_BTYPE_BUT, + 0, + ICON_BLANK1, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Single-User Copy"), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Duplicate the data-block and assign the newly created copy")); + + if (ID_REAL_USERS(id) <= 1) { + UI_but_flag_enable(but, UI_BUT_DISABLED); + but->disabled_info = TIP_("Data-block already is a single-user"); + /* No need for further setup. */ + return but; + } + + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ALONE)); + ID *idfrom = template_ui->ptr.owner_id; + bool disabled = false; + + if (!RNA_property_editable_info(&template_ui->ptr, template_ui->prop, &but->disabled_info)) { + disabled = true; + } + if (!BKE_id_copy_is_allowed(id)) { + but->disabled_info = TIP_("Data-blocks of this type cannot be copied"); + disabled = true; + } + /* object in editmode - don't change data */ + if (idfrom && GS(idfrom->name) == ID_OB && (((Object *)idfrom)->mode & OB_MODE_EDIT)) { + but->disabled_info = TIP_("Cannot change object data in Edit Mode"); + disabled = true; + } + + if (disabled) { + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + + return but; +} +#endif + +static void template_id_use_fake_user_button(uiBlock *block, PointerRNA *idptr) +{ + const bool use_fake_user = ID_FAKE_USERS(idptr->data) > 0; + uiBut *but = uiDefIconTextButR( + block, + UI_BTYPE_ICON_TOGGLE, + 0, + ICON_FAKE_USER_OFF, + use_fake_user ? CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Fake User") : + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Fake User"), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + idptr, + "use_fake_user", + -1, + 0, + 0, + -1, + -1, + TIP_("When set, ensures the data-block is kept when reloading the file, even if not used at " + "all")); + + if ((ELEM(GS(((ID *)idptr->data)->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) { + but->disabled_info = TIP_("Data-block type does not support fake user"); + UI_but_flag_enable(but, UI_BUT_DISABLED); + } +} + +enum TemplateIDCreateType { + TEMPLATE_ID_CREATE_NEW, + TEMPLATE_ID_CREATE_DUPLICATE, +}; + +static uiBut *template_id_new_button(uiBlock *block, + const ID *id, + TemplateID *template_ui, + enum TemplateIDCreateType create_type, + StructRNA *type, + const bool id_open, + const bool use_tab_but, + int but_height) +{ uiBut *but; const int w = id ? UI_UNIT_X : id_open ? UI_UNIT_X * 3 : UI_UNIT_X * 6; const int but_type = use_tab_but ? UI_BTYPE_TAB : UI_BTYPE_BUT; @@ -820,54 +1022,384 @@ static uiBut *template_id_def_new_but(uiBlock *block, BLT_I18NCONTEXT_ID_POINTCLOUD, BLT_I18NCONTEXT_ID_VOLUME, BLT_I18NCONTEXT_ID_SIMULATION, ); + BLT_I18N_MSGID_MULTI_CTXT("Duplicate", + BLT_I18NCONTEXT_DEFAULT, + BLT_I18NCONTEXT_ID_SCENE, + BLT_I18NCONTEXT_ID_OBJECT, + BLT_I18NCONTEXT_ID_MESH, + BLT_I18NCONTEXT_ID_CURVE, + BLT_I18NCONTEXT_ID_METABALL, + BLT_I18NCONTEXT_ID_MATERIAL, + BLT_I18NCONTEXT_ID_TEXTURE, + BLT_I18NCONTEXT_ID_IMAGE, + BLT_I18NCONTEXT_ID_LATTICE, + BLT_I18NCONTEXT_ID_LIGHT, + BLT_I18NCONTEXT_ID_CAMERA, + BLT_I18NCONTEXT_ID_WORLD, + BLT_I18NCONTEXT_ID_SCREEN, + BLT_I18NCONTEXT_ID_TEXT, ); + BLT_I18N_MSGID_MULTI_CTXT("Duplicate", + BLT_I18NCONTEXT_ID_SPEAKER, + BLT_I18NCONTEXT_ID_SOUND, + BLT_I18NCONTEXT_ID_ARMATURE, + BLT_I18NCONTEXT_ID_ACTION, + BLT_I18NCONTEXT_ID_NODETREE, + BLT_I18NCONTEXT_ID_BRUSH, + BLT_I18NCONTEXT_ID_PARTICLESETTINGS, + BLT_I18NCONTEXT_ID_GPENCIL, + BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, + BLT_I18NCONTEXT_ID_WORKSPACE, + BLT_I18NCONTEXT_ID_LIGHTPROBE, + BLT_I18NCONTEXT_ID_HAIR, + BLT_I18NCONTEXT_ID_POINTCLOUD, + BLT_I18NCONTEXT_ID_VOLUME, + BLT_I18NCONTEXT_ID_SIMULATION, ); /* Note: BLT_I18N_MSGID_MULTI_CTXT takes a maximum number of parameters, * check the definition to see if a new call must be added when the limit * is exceeded. */ - if (newop) { + const char *text; + const char *op; + BIFIconID icon; + + switch (create_type) { + case TEMPLATE_ID_CREATE_NEW: + icon = ICON_ADD; + text = CTX_IFACE_(template_id_context(type), "New"); + op = template_ui->new_op; + break; + case TEMPLATE_ID_CREATE_DUPLICATE: + icon = ICON_DUPLICATE; + text = CTX_IFACE_(template_id_context(type), "Duplicate"); + op = template_ui->duplicate_op; + break; + } + + const bool icon_only = use_tab_but; + if (icon_only) { + text = ""; + } + + if (op) { + but = uiDefIconTextButO( + block, but_type, op, WM_OP_INVOKE_DEFAULT, icon, text, 0, 0, w, but_height, NULL); + UI_but_funcN_set( + but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ADD_NEW)); + + if (!RNA_property_editable_info(&template_ui->ptr, template_ui->prop, &but->disabled_info)) { + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + } + else { + but = uiDefIconTextBut(block, + but_type, + 0, + icon, + text, + 0, + 0, + w, + but_height, + NULL, + 0, + 0, + 0, + 0, + TIP_("Create a new data-block")); + but->disabled_info = TIP_("Creating a new data-block is not supported here"); + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + if (icon_only) { + UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT); + } + +#ifndef WITH_INTERNATIONAL + UNUSED_VARS(type); +#endif + + return but; +} + +static void template_id_unlink_button(uiBlock *block, + TemplateID *template_ui, + bool hide_if_disabled) +{ + const char *disable_info; + const bool is_menu = ui_block_is_menu(block); + const bool editable = RNA_property_editable_info( + &template_ui->ptr, template_ui->prop, &disable_info); + /* allow unlink if 'unlinkop' is passed, even when 'PROP_NEVER_UNLINK' is set */ + uiBut *but = NULL; + + if (hide_if_disabled && !editable) { + /* Add no button. */ + } + else if (template_ui->unlink_op) { but = uiDefIconTextButO(block, - but_type, - newop, + UI_BTYPE_BUT, + template_ui->unlink_op, WM_OP_INVOKE_DEFAULT, - (id && !use_tab_but) ? ICON_DUPLICATE : ICON_ADD, - (id) ? "" : CTX_IFACE_(template_id_context(type), "New"), + ICON_X, + is_menu ? NULL : "", + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL); + /* so we can access the template from operators, font unlinking needs this */ + UI_but_funcN_set(but, NULL, MEM_dupallocN(template_ui), NULL); + } + else { + const bool never_unlink = RNA_property_flag(template_ui->prop) & + (PROP_NEVER_UNLINK | PROP_NEVER_NULL); + + if (!never_unlink || !hide_if_disabled) { + but = uiDefIconTextBut(block, + UI_BTYPE_BUT, + 0, + ICON_X, + is_menu ? CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Unlink") : "", + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Remove this usage of the data-block")); + if (!never_unlink) { + UI_but_funcN_set( + but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_DELETE)); + } + if (!is_menu) { + UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT); + } + } + + if (but && never_unlink) { + but->disabled_info = TIP_("Property must never be in an unlinked state"); + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + } + + if (but) { + if (!editable) { + but->disabled_info = disable_info; + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + } +} + +static void template_id_open_button(uiBlock *block, + ID *id, + TemplateID *template_ui, + const bool compact) +{ + const bool is_menu = ui_block_is_menu(block); + const int w = compact ? UI_UNIT_X * 3 : UI_UNIT_X * 6; + char text[UI_MAX_NAME_STR] = ""; + const bool icon_only = !is_menu && id; + uiBut *but; + + if (!icon_only) { + BLI_snprintf(text, + sizeof(text), + "%s%s", + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open"), + is_menu ? "..." : ""); + } + + if (template_ui->open_op) { + but = uiDefIconTextButO(block, + UI_BTYPE_BUT, + template_ui->open_op, + WM_OP_INVOKE_DEFAULT, + ICON_FILEBROWSER, + text, 0, 0, w, - but_height, + UI_UNIT_Y, NULL); UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ADD_NEW)); + but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OPEN)); } else { but = uiDefIconTextBut(block, - but_type, + UI_BTYPE_BUT, 0, - (id && !use_tab_but) ? ICON_DUPLICATE : ICON_ADD, - (id) ? "" : CTX_IFACE_(template_id_context(type), "New"), + ICON_FILEBROWSER, + text, 0, 0, w, - but_height, + UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ADD_NEW)); + but->disabled_info = TIP_("Browsing for a new data-block is not supported here"); + UI_but_flag_enable(but, UI_BUT_DISABLED); } - if ((idfrom && idfrom->lib) || !editable) { + if (!RNA_property_editable_info(&template_ui->ptr, template_ui->prop, &but->disabled_info)) { UI_but_flag_enable(but, UI_BUT_DISABLED); } +} -#ifndef WITH_INTERNATIONAL - UNUSED_VARS(type); +static void template_id_unpack_button(uiBlock *block, ID *id) +{ + wmOperatorType *optype = WM_operatortype_find("FILE_OT_unpack_item", false); + uiBut *but; + + but = uiDefIconTextButO_ptr(block, + UI_BTYPE_BUT, + optype, + WM_OP_INVOKE_REGION_WIN, + ICON_PACKAGE, + NULL, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL); + + if (!BKE_packedfile_id_check(id)) { + but->disabled_info = TIP_("File is not packed"); + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + UI_but_operator_ptr_get(but); + + RNA_string_set(but->opptr, "id_name", id->name + 2); + RNA_int_set(but->opptr, "id_type", GS(id->name)); +} + +static void template_id_user_count_label(uiLayout *layout, const ID *id) +{ + char numstr[UI_MAX_NAME_STR]; + BLI_snprintf(numstr, + sizeof(numstr), + "%d %s", + ID_REAL_USERS(id), + ID_REAL_USERS(id) > 1 ? IFACE_("Users") : IFACE_("User")); + uiItemL(layout, numstr, ICON_NONE); +} + +static void template_id_menu(bContext *C, uiLayout *layout, void *arg) +{ + /* Button that spawned the menu. */ + const uiBut *menu_parent_but = arg; + TemplateID *template_ui = menu_parent_but->func_argN; + PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + ID *id = idptr.data; + uiBlock *block = uiLayoutGetBlock(layout); + + BLI_assert(id); + + template_id_new_button( + block, id, template_ui, TEMPLATE_ID_CREATE_NEW, idptr.type, false, false, UI_UNIT_X); + template_id_new_button( + block, id, template_ui, TEMPLATE_ID_CREATE_DUPLICATE, idptr.type, false, false, UI_UNIT_X); + template_id_unlink_button(block, template_ui, false); + +#ifdef USE_TEMPLATE_ID_MAKE_SINGLE_USER + template_id_make_single_user_button(block, id, template_ui); #endif + template_id_use_fake_user_button(block, &idptr); - return but; + if (template_ui->open_op || BKE_packedfile_id_check(id)) { + uiItemS(layout); + + template_id_open_button(block, id, template_ui, false); + template_id_unpack_button(block, id); + } + + /* Library operators. */ + if (ID_IS_OVERRIDE_LIBRARY(id)) { + uiItemS(layout); + + template_id_library_overridden_button(block, id, template_ui, UI_ID_LIB_OVERRIDE_RESET); + template_id_library_overridden_button(block, id, template_ui, UI_ID_LIB_OVERRIDE_REMOVE); + } + else if (ID_IS_LINKED(id)) { + uiItemS(layout); + + Main *bmain = CTX_data_main(C); + template_id_linked_operation_button(block, bmain, id, template_ui, UI_ID_MAKE_LOCAL); + template_id_linked_operation_button(block, bmain, id, template_ui, UI_ID_LIB_OVERRIDE_ADD); + } + + uiItemS(layout); + template_id_user_count_label(layout, id); +} + +static void template_id_name_button( + uiBlock *block, StructRNA *type, TemplateID *template_ui, int flag, const bool hide_extras) +{ + PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + ID *id = idptr.data; + BIFIconID lib_icon = UI_icon_from_library(id); + + char name[UI_MAX_NAME_STR] = ""; + uiBut *but = uiDefIconTextButR(block, + UI_BTYPE_TEXT, + 0, + lib_icon, + name, + 0, + 0, + TEMPLATE_SEARCH_TEXTBUT_WIDTH, + TEMPLATE_SEARCH_TEXTBUT_HEIGHT, + &idptr, + "name", + -1, + 0, + 0, + 0, + 0, + RNA_struct_ui_description(type)); + /* Note: Also needed for the extra icons below (their operators access the TemplateID). */ + UI_but_funcN_set( + but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_RENAME)); + + const bool user_alert = (id->us <= 0); + if (user_alert) { + UI_but_flag_enable(but, UI_BUT_REDALERT); + } + + if (hide_extras) { + return; + } + + if (template_ui->duplicate_op && (flag & UI_ID_ADD_NEW)) { + UI_but_extra_operator_icon_add( + but, template_ui->duplicate_op, WM_OP_INVOKE_DEFAULT, ICON_DUPLICATE); + } + + if (id && (flag & UI_ID_DELETE)) { + const bool never_unlink = RNA_property_flag(template_ui->prop) & + (PROP_NEVER_UNLINK | PROP_NEVER_NULL); + if (template_ui->unlink_op) { + UI_but_extra_operator_icon_add(but, template_ui->unlink_op, WM_OP_INVOKE_DEFAULT, ICON_X); + } + else if (!never_unlink) { + UI_but_extra_operator_icon_add(but, "ED_OT_lib_unlink", WM_OP_INVOKE_DEFAULT, ICON_X); + } + } + + /* Disable fake user icon for now, only have it in the menu. */ + const bool add_extra_fake_user_icon = false; + if (add_extra_fake_user_icon && id->lib == NULL && + !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) { + UI_but_extra_operator_icon_add(but, + "ED_OT_lib_fake_user_toggle", + WM_OP_INVOKE_DEFAULT, + ID_FAKE_USERS(id) ? ICON_FAKE_USER_ON : ICON_FAKE_USER_OFF); + } } static void template_ID(const bContext *C, @@ -875,9 +1407,6 @@ static void template_ID(const bContext *C, TemplateID *template_ui, StructRNA *type, int flag, - const char *newop, - const char *openop, - const char *unlinkop, const char *text, const bool live_icon, const bool hide_buttons) @@ -885,15 +1414,15 @@ static void template_ID(const bContext *C, uiBut *but; uiBlock *block; PointerRNA idptr; - // ListBase *lb; // UNUSED - ID *id, *idfrom; + ID *id; const bool editable = RNA_property_editable(&template_ui->ptr, template_ui->prop); const bool use_previews = template_ui->preview = (flag & UI_ID_PREVIEWS) != 0; idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); id = idptr.data; - idfrom = template_ui->ptr.owner_id; - // lb = template_ui->idlb; + + /* Allow opertators to take the ID from context. */ + uiLayoutSetContextPointer(layout, "id", &idptr); block = uiLayoutGetBlock(layout); UI_block_align_begin(block); @@ -923,277 +1452,39 @@ static void template_ID(const bContext *C, /* text button with name */ if (id) { - char name[UI_MAX_NAME_STR]; - const bool user_alert = (id->us <= 0); - - // text_idbutton(id, name); - name[0] = '\0'; - but = uiDefButR(block, - UI_BTYPE_TEXT, - 0, - name, - 0, - 0, - TEMPLATE_SEARCH_TEXTBUT_WIDTH, - TEMPLATE_SEARCH_TEXTBUT_HEIGHT, - &idptr, - "name", - -1, - 0, - 0, - -1, - -1, - RNA_struct_ui_description(type)); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_RENAME)); - if (user_alert) { - UI_but_flag_enable(but, UI_BUT_REDALERT); - } - - if (id->lib) { - if (id->tag & LIB_TAG_INDIRECT) { - but = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_LIBRARY_DATA_INDIRECT, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Indirect library data-block, cannot change")); - 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) || - (idfrom && idfrom->lib)); - but = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_LIBRARY_DATA_DIRECT, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Direct linked library data-block, click to make local, " - "Shift + Click to create a library override")); - if (disabled) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - else { - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_LOCAL)); - } - } - } - else if (ID_IS_OVERRIDE_LIBRARY(id)) { - but = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_LIBRARY_DATA_OVERRIDE, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Library override of linked data-block, click to make fully local")); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OVERRIDE)); - } - - if ((ID_REAL_USERS(id) > 1) && (hide_buttons == false)) { - char numstr[32]; - short numstr_len; - - numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", ID_REAL_USERS(id)); - - but = uiDefBut( - block, - UI_BTYPE_BUT, - 0, - numstr, - 0, - 0, - numstr_len * 0.2f * UI_UNIT_X + UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Display number of users of this data (click to make a single-user copy)")); - but->flag |= UI_BUT_UNDO; - - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ALONE)); - if ((!BKE_id_copy_is_allowed(id)) || (idfrom && idfrom->lib) || (!editable) || - /* object in editmode - don't change data */ - (idfrom && GS(idfrom->name) == ID_OB && (((Object *)idfrom)->mode & OB_MODE_EDIT))) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - } - - if (user_alert) { - UI_but_flag_enable(but, UI_BUT_REDALERT); - } - - if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS)) && - (hide_buttons == false)) { - uiDefIconButR(block, - UI_BTYPE_ICON_TOGGLE, - 0, - ICON_FAKE_USER_OFF, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - &idptr, - "use_fake_user", - -1, - 0, - 0, - -1, - -1, - NULL); - } + template_id_name_button(block, type, template_ui, flag, hide_buttons); } - - if ((flag & UI_ID_ADD_NEW) && (hide_buttons == false)) { - template_id_def_new_but( - block, id, template_ui, type, newop, editable, flag & UI_ID_OPEN, false, UI_UNIT_X); + /* If no ID is set, show a "new" button instead of a text button. */ + else if ((flag & UI_ID_ADD_NEW) && (hide_buttons == false)) { + template_id_new_button( + block, id, template_ui, TEMPLATE_ID_CREATE_NEW, type, flag & UI_ID_OPEN, false, UI_UNIT_X); } - /* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack. - * Only for images, sound and fonts */ - if (id && BKE_packedfile_id_check(id)) { - but = uiDefIconButO(block, - UI_BTYPE_BUT, - "FILE_OT_unpack_item", - WM_OP_INVOKE_REGION_WIN, - ICON_PACKAGE, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - TIP_("Packed File, click to unpack")); - UI_but_operator_ptr_get(but); - - RNA_string_set(but->opptr, "id_name", id->name + 2); - RNA_int_set(but->opptr, "id_type", GS(id->name)); + if ((flag & UI_ID_OPEN) && !id) { + template_id_open_button(block, id, template_ui, flag & UI_ID_ADD_NEW); } - else if (flag & UI_ID_OPEN) { - const int w = id ? UI_UNIT_X : (flag & UI_ID_ADD_NEW) ? UI_UNIT_X * 3 : UI_UNIT_X * 6; - - if (openop) { - but = uiDefIconTextButO(block, - UI_BTYPE_BUT, - openop, - WM_OP_INVOKE_DEFAULT, - ICON_FILEBROWSER, - (id) ? "" : IFACE_("Open"), - 0, - 0, - w, - UI_UNIT_Y, - NULL); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OPEN)); - } - else { - but = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_FILEBROWSER, - (id) ? "" : IFACE_("Open"), - 0, - 0, - w, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - NULL); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OPEN)); - } - if ((idfrom && idfrom->lib) || !editable) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } + if (template_ui->idcode == ID_TE) { + uiTemplateTextureShow(layout, C, &template_ui->ptr, template_ui->prop); } - /* delete button */ - /* don't use RNA_property_is_unlink here */ - if (id && (flag & UI_ID_DELETE) && (hide_buttons == false)) { - /* allow unlink if 'unlinkop' is passed, even when 'PROP_NEVER_UNLINK' is set */ - but = NULL; - - if (unlinkop) { - but = uiDefIconButO(block, - UI_BTYPE_BUT, - unlinkop, - WM_OP_INVOKE_DEFAULT, - ICON_X, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL); - /* so we can access the template from operators, font unlinking needs this */ - UI_but_funcN_set(but, NULL, MEM_dupallocN(template_ui), NULL); - } - else { - if ((RNA_property_flag(template_ui->prop) & PROP_NEVER_UNLINK) == 0) { - but = uiDefIconBut( - block, - UI_BTYPE_BUT, - 0, - ICON_X, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Unlink data-block " - "(Shift + Click to set users to zero, data will then not be saved)")); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_DELETE)); - - if (RNA_property_flag(template_ui->prop) & PROP_NEVER_NULL) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - } - } - - if (but) { - if ((idfrom && idfrom->lib) || !editable) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - } + if (id && !hide_buttons) { + /* Additional operations menu ("Make Local", overrides, etc). */ + but = uiDefIconMenuBut(block, + template_id_menu, + NULL, + ICON_DOWNARROW_HLT, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + TIP_("Show more operations for the selected data-block")); + UI_but_type_set_menu_from_pulldown(but); + /* Same hack as ui_item_menu() to allow allocated arg. */ + but->poin = (char *)but; + but->func_argN = MEM_dupallocN(template_ui); } - if (template_ui->idcode == ID_TE) { - uiTemplateTextureShow(layout, C, &template_ui->ptr, template_ui->prop); - } UI_block_align_end(block); } @@ -1212,7 +1503,6 @@ static void template_ID_tabs(const bContext *C, TemplateID *template, StructRNA *type, int flag, - const char *newop, const char *menu) { const ARegion *region = CTX_wm_region(C); @@ -1260,22 +1550,20 @@ static void template_ID_tabs(const bContext *C, BLI_freelistN(&ordered); if (flag & UI_ID_ADD_NEW) { - const bool editable = RNA_property_editable(&template->ptr, template->prop); uiBut *but; if (active_ptr.type) { type = active_ptr.type; } - but = template_id_def_new_but(block, - active_ptr.data, - template, - type, - newop, - editable, - flag & UI_ID_OPEN, - true, - but_height); + but = template_id_new_button(block, + active_ptr.data, + template, + TEMPLATE_ID_CREATE_NEW, + type, + flag & UI_ID_OPEN, + true, + but_height); UI_but_drawflag_enable(but, but_align); } } @@ -1285,6 +1573,7 @@ static void ui_template_id(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *newop, + const char *duplicateop, const char *openop, const char *unlinkop, /* Only respected by tabs (use_tabs). */ @@ -1314,6 +1603,10 @@ static void ui_template_id(uiLayout *layout, template_ui = MEM_callocN(sizeof(TemplateID), "TemplateID"); template_ui->ptr = *ptr; template_ui->prop = prop; + template_ui->new_op = newop; + template_ui->duplicate_op = duplicateop; + template_ui->unlink_op = unlinkop; + template_ui->open_op = openop; template_ui->prv_rows = prv_rows; template_ui->prv_cols = prv_cols; template_ui->scale = scale; @@ -1325,7 +1618,7 @@ static void ui_template_id(uiLayout *layout, template_ui->filter = 0; } - if (newop) { + if (newop || duplicateop) { flag |= UI_ID_ADD_NEW; } if (openop) { @@ -1343,21 +1636,11 @@ static void ui_template_id(uiLayout *layout, if (template_ui->idlb) { if (use_tabs) { layout = uiLayoutRow(layout, true); - template_ID_tabs(C, layout, template_ui, type, flag, newop, menu); + template_ID_tabs(C, layout, template_ui, type, flag, menu); } else { layout = uiLayoutRow(layout, true); - template_ID(C, - layout, - template_ui, - type, - flag, - newop, - openop, - unlinkop, - text, - live_icon, - hide_buttons); + template_ID(C, layout, template_ui, type, flag, text, live_icon, hide_buttons); } } @@ -1369,6 +1652,7 @@ void uiTemplateID(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *newop, + const char *duplicateop, const char *openop, const char *unlinkop, int filter, @@ -1380,6 +1664,7 @@ void uiTemplateID(uiLayout *layout, ptr, propname, newop, + duplicateop, openop, unlinkop, NULL, @@ -1409,6 +1694,7 @@ void uiTemplateIDBrowse(uiLayout *layout, ptr, propname, newop, + NULL, openop, unlinkop, NULL, @@ -1440,6 +1726,7 @@ void uiTemplateIDPreview(uiLayout *layout, ptr, propname, newop, + NULL, openop, unlinkop, NULL, @@ -1472,6 +1759,7 @@ void uiTemplateGpencilColorPreview(uiLayout *layout, NULL, NULL, NULL, + NULL, UI_ID_BROWSE | UI_ID_PREVIEWS | UI_ID_DELETE, rows, cols, @@ -1500,6 +1788,7 @@ void uiTemplateIDTabs(uiLayout *layout, newop, NULL, NULL, + NULL, menu, NULL, UI_ID_BROWSE | UI_ID_RENAME, @@ -1659,35 +1948,25 @@ static void template_search_add_button_searchmenu(const bContext *C, static void template_search_add_button_name(uiBlock *block, PointerRNA *active_ptr, - const StructRNA *type) + const StructRNA *type, + const char *newop, + const char *unlinkop) { - uiDefAutoButR(block, - active_ptr, - RNA_struct_name_property(type), - 0, - "", - ICON_NONE, - 0, - 0, - TEMPLATE_SEARCH_TEXTBUT_WIDTH, - TEMPLATE_SEARCH_TEXTBUT_HEIGHT); -} - -static void template_search_add_button_operator(uiBlock *block, - const char *const operator_name, - const int opcontext, - const int icon, - const bool editable) -{ - if (!operator_name) { - return; + uiBut *but = uiDefAutoButR(block, + active_ptr, + RNA_struct_name_property(type), + 0, + "", + ICON_NONE, + 0, + 0, + TEMPLATE_SEARCH_TEXTBUT_WIDTH, + TEMPLATE_SEARCH_TEXTBUT_HEIGHT); + if (newop) { + UI_but_extra_operator_icon_add(but, newop, WM_OP_INVOKE_DEFAULT, ICON_DUPLICATE); } - - uiBut *but = uiDefIconButO( - block, UI_BTYPE_BUT, operator_name, opcontext, icon, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL); - - if (!editable) { - UI_but_drawflag_enable(but, UI_BUT_DISABLED); + if (unlinkop) { + UI_but_extra_operator_icon_add(but, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X); } } @@ -1713,10 +1992,7 @@ static void template_search_buttons(const bContext *C, UI_block_align_begin(block); template_search_add_button_searchmenu(C, layout, block, template_search, editable, false); - template_search_add_button_name(block, &active_ptr, type); - template_search_add_button_operator( - block, newop, WM_OP_INVOKE_DEFAULT, ICON_DUPLICATE, editable); - template_search_add_button_operator(block, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, editable); + template_search_add_button_name(block, &active_ptr, type, newop, unlinkop); UI_block_align_end(block); } @@ -2011,7 +2287,7 @@ static void set_constraint_expand_flag(const bContext *UNUSED(C), Panel *panel, /** * Function with void * argument for #uiListPanelIDFromDataFunc. * - * \note: Constraint panel types are assumed to be named with the struct name field + * \note Constraint panel types are assumed to be named with the struct name field * concatenated to the defined prefix. */ static void object_constraint_panel_id(void *md_link, char *r_name) @@ -2639,7 +2915,7 @@ static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *co } else { /* enabled */ - UI_block_emboss_set(block, UI_EMBOSS_NONE); + UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); uiItemR(layout, &ptr, "mute", 0, "", 0); UI_block_emboss_set(block, UI_EMBOSS); @@ -6170,6 +6446,10 @@ void uiTemplateList(uiLayout *layout, org_i, flt_flag); + /* Items should be able to set context pointers for the layout. But the list-row button + * swallows events, so it needs the context storage too for handlers to see it. */ + but->context = uiLayoutGetContextStore(sub); + /* If we are "drawing" active item, set all labels as active. */ if (i == activei) { ui_layout_list_set_labels_active(sub); @@ -7184,6 +7464,7 @@ void uiTemplateCacheFile(uiLayout *layout, ptr, propname, NULL, + NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 9c7b112855f..4d81b1edf0c 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -264,7 +264,7 @@ typedef struct uiWidgetType { /* converted colors for state */ uiWidgetColors wcol; - void (*state)(struct uiWidgetType *, int state, int drawflag, char emboss); + void (*state)(struct uiWidgetType *, int state, int drawflag, eUIEmbossType emboss); void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign); void (*custom)(uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign); void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *); @@ -2520,8 +2520,14 @@ static void widget_active_color(uiWidgetColors *wcol) static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wcol_state, int state, - int drawflag) + int drawflag, + const eUIEmbossType emboss) { + /* Explicitly require #UI_EMBOSS_NONE_OR_STATUS for color blending with no emboss. */ + if (emboss == UI_EMBOSS_NONE) { + return NULL; + } + if (drawflag & UI_BUT_ANIMATED_CHANGED) { return wcol_state->inner_changed_sel; } @@ -2541,7 +2547,7 @@ static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wco } /* copy colors from theme, and set changes in it based on state */ -static void widget_state(uiWidgetType *wt, int state, int drawflag, char emboss) +static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss) { uiWidgetStateColors *wcol_state = wt->wcol_state; @@ -2557,7 +2563,7 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, char emboss) wt->wcol = *(wt->wcol_theme); - const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag); + const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag, emboss); if (state & UI_SELECT) { copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel); @@ -2619,14 +2625,14 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, char emboss) * \{ */ /* sliders use special hack which sets 'item' as inner when drawing filling */ -static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, char emboss) +static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss) { uiWidgetStateColors *wcol_state = wt->wcol_state; /* call this for option button */ widget_state(wt, state, drawflag, emboss); - const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag); + const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag, emboss); if (color_blend != NULL) { /* Set the slider 'item' so that it reflects state settings too. * De-saturate so the color of the slider doesn't conflict with the blend color, @@ -2642,7 +2648,10 @@ static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, ch } /* labels use theme colors for text */ -static void widget_state_option_menu(uiWidgetType *wt, int state, int drawflag, char emboss) +static void widget_state_option_menu(uiWidgetType *wt, + int state, + int drawflag, + eUIEmbossType emboss) { const bTheme *btheme = UI_GetTheme(); @@ -2662,7 +2671,7 @@ static void widget_state_option_menu(uiWidgetType *wt, int state, int drawflag, static void widget_state_nothing(uiWidgetType *wt, int UNUSED(state), int UNUSED(drawflag), - char UNUSED(emboss)) + eUIEmbossType UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); } @@ -2671,7 +2680,7 @@ static void widget_state_nothing(uiWidgetType *wt, static void widget_state_pulldown(uiWidgetType *wt, int UNUSED(state), int UNUSED(drawflag), - char UNUSED(emboss)) + eUIEmbossType UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); } @@ -2680,7 +2689,7 @@ static void widget_state_pulldown(uiWidgetType *wt, static void widget_state_pie_menu_item(uiWidgetType *wt, int state, int UNUSED(drawflag), - char UNUSED(emboss)) + eUIEmbossType UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); @@ -2715,7 +2724,7 @@ static void widget_state_pie_menu_item(uiWidgetType *wt, static void widget_state_menu_item(uiWidgetType *wt, int state, int UNUSED(drawflag), - char UNUSED(emboss)) + eUIEmbossType UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); @@ -2906,12 +2915,12 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const const bool is_color_gamma = ui_but_is_color_gamma(but); /* Initialize for compatibility. */ - copy_v3_v3(hsv, cpicker->color_data); + copy_v3_v3(hsv, cpicker->hsv_perceptual); /* Compute current hue. */ ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + ui_scene_linear_to_perceptual_space(but, rgb); + ui_color_picker_rgb_to_hsv_compat(rgb, hsv); CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */ @@ -2928,8 +2937,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const } const float hsv_center[3] = {0.0f, 0.0f, hsv[2]}; - ui_color_picker_to_rgb_v(hsv_center, rgb_center); - ui_color_picker_to_scene_linear_space(but, rgb_center); + ui_color_picker_hsv_to_rgb(hsv_center, rgb_center); + ui_perceptual_to_scene_linear_space(but, rgb_center); if (!is_color_gamma) { ui_block_cm_to_display_space_v3(but->block, rgb_center); @@ -2956,8 +2965,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const rect, centx + co * radius, centy + si * radius, hsv_ang, hsv_ang + 1); hsv_ang[2] = hsv[2]; - ui_color_picker_to_rgb_v(hsv_ang, rgb_ang); - ui_color_picker_to_scene_linear_space(but, rgb_ang); + ui_color_picker_hsv_to_rgb(hsv_ang, rgb_ang); + ui_perceptual_to_scene_linear_space(but, rgb_ang); if (!is_color_gamma) { ui_block_cm_to_display_space_v3(but->block, rgb_ang); @@ -2987,10 +2996,10 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const GPU_line_smooth(false); /* cursor */ - copy_v3_v3(hsv, cpicker->color_data); + copy_v3_v3(hsv, cpicker->hsv_perceptual); ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + ui_scene_linear_to_perceptual_space(but, rgb); + ui_color_picker_rgb_to_hsv_compat(rgb, hsv); float xpos, ypos; ui_hsvcircle_pos_from_vals(cpicker, rect, hsv, &xpos, &ypos); @@ -3212,14 +3221,14 @@ static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect) float rgb[3]; float x = 0.0f, y = 0.0f; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; float hsv_n[3]; /* Initialize for compatibility. */ copy_v3_v3(hsv_n, hsv); ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); + ui_scene_linear_to_perceptual_space(but, rgb); rgb_to_hsv_compat_v(rgb, hsv_n); ui_draw_gradient(rect, hsv_n, hsv_but->gradient_type, 1.0f); @@ -3251,7 +3260,7 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect) float rgb[3], hsv[3], v; ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); + ui_scene_linear_to_perceptual_space(but, rgb); if (hsv_but->gradient_type == UI_GRAD_L_ALT) { rgb_to_hsl_v(rgb, hsv); @@ -4064,7 +4073,7 @@ static void widget_optionbut(uiWidgetColors *wcol, } /* labels use Editor theme colors for text */ -static void widget_state_label(uiWidgetType *wt, int state, int drawflag, char emboss) +static void widget_state_label(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss) { if (state & UI_BUT_LIST_ITEM) { /* Override default label theme's colors. */ @@ -4524,8 +4533,9 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu break; } } - else if (but->emboss == UI_EMBOSS_NONE) { - /* "nothing" */ + else if (ELEM(but->emboss, UI_EMBOSS_NONE, UI_EMBOSS_NONE_OR_STATUS)) { + /* Use the same widget types for both no emboss types. Later on, + * #UI_EMBOSS_NONE_OR_STATUS will blend state colors if they apply. */ switch (but->type) { case UI_BTYPE_LABEL: wt = widget_type(UI_WTYPE_ICON_LABEL); diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index a5999962e09..7de0ec0255f 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -109,14 +109,13 @@ typedef struct v2dViewPanData { static bool view_pan_poll(bContext *C) { ARegion *region = CTX_wm_region(C); - View2D *v2d; /* check if there's a region in context to work with */ if (region == NULL) { return false; } - v2d = ®ion->v2d; + View2D *v2d = ®ion->v2d; /* check that 2d-view can pan */ if ((v2d->keepofs & V2D_LOCKOFS_X) && (v2d->keepofs & V2D_LOCKOFS_Y)) { @@ -191,10 +190,7 @@ static void view_pan_apply(bContext *C, wmOperator *op) /* cleanup temp customdata */ static void view_pan_exit(wmOperator *op) { - if (op->customdata) { - MEM_freeN(op->customdata); - op->customdata = NULL; - } + MEM_SAFE_FREE(op->customdata); } /** \} */ @@ -216,14 +212,12 @@ static int view_pan_exec(bContext *C, wmOperator *op) static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *window = CTX_wm_window(C); - v2dViewPanData *vpd; - View2D *v2d; /* set up customdata */ view_pan_init(C, op); - vpd = op->customdata; - v2d = vpd->v2d; + v2dViewPanData *vpd = op->customdata; + View2D *v2d = vpd->v2d; /* set initial settings */ vpd->startx = vpd->lastx = event->x; @@ -787,7 +781,6 @@ static void view_zoom_axis_lock_defaults(bContext *C, bool r_do_zoom_xy[2]) static bool view_zoom_poll(bContext *C) { ARegion *region = CTX_wm_region(C); - View2D *v2d; /* check if there's a region in context to work with */ if (region == NULL) { @@ -799,7 +792,7 @@ static bool view_zoom_poll(bContext *C) return false; } - v2d = ®ion->v2d; + View2D *v2d = ®ion->v2d; /* check that 2d-view is zoomable */ if ((v2d->keepzoom & V2D_LOCKZOOM_X) && (v2d->keepzoom & V2D_LOCKZOOM_Y)) { @@ -836,12 +829,12 @@ static void view_zoomstep_apply_ex(bContext *C, ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; const rctf cur_old = v2d->cur; - float dx, dy; const int snap_test = ED_region_snap_size_test(region); /* calculate amount to move view by, ensuring symmetry so the * old zoom level is restored after zooming back the same amount */ + float dx, dy; if (facx >= 0.0f) { dx = BLI_rctf_size_x(&v2d->cur) * facx; dy = BLI_rctf_size_y(&v2d->cur) * facy; @@ -955,10 +948,7 @@ static void view_zoomstep_exit(wmOperator *op) { UI_view2d_zoom_cache_reset(); - if (op->customdata) { - MEM_freeN(op->customdata); - op->customdata = NULL; - } + MEM_SAFE_FREE(op->customdata); } /* this operator only needs this single callback, where it calls the view_zoom_*() methods */ @@ -1107,15 +1097,14 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op) { v2dViewZoomData *vzd = op->customdata; View2D *v2d = vzd->v2d; - float dx, dy; const int snap_test = ED_region_snap_size_test(vzd->region); const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); const bool zoom_to_pos = use_cursor_init && vzd->zoom_to_mouse_pos; /* get amount to move view by */ - dx = RNA_float_get(op->ptr, "deltax") / U.dpi_fac; - dy = RNA_float_get(op->ptr, "deltay") / U.dpi_fac; + float dx = RNA_float_get(op->ptr, "deltax") / U.dpi_fac; + float dy = RNA_float_get(op->ptr, "deltay") / U.dpi_fac; if (U.uiflag & USER_ZOOM_INVERT) { dx *= -1; @@ -1223,14 +1212,12 @@ static int view_zoomdrag_exec(bContext *C, wmOperator *op) static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *window = CTX_wm_window(C); - v2dViewZoomData *vzd; - View2D *v2d; /* set up customdata */ view_zoomdrag_init(C, op); - vzd = op->customdata; - v2d = vzd->v2d; + v2dViewZoomData *vzd = op->customdata; + View2D *v2d = vzd->v2d; if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { ARegion *region = CTX_wm_region(C); @@ -1242,20 +1229,18 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *even } if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) { - float dx, dy, fac; - vzd->lastx = event->prevx; vzd->lasty = event->prevy; /* As we have only 1D information (magnify value), feed both axes * with magnify information that is stored in x axis */ - fac = 0.01f * (event->prevx - event->x); - dx = fac * BLI_rctf_size_x(&v2d->cur) / 10.0f; + float fac = 0.01f * (event->prevx - event->x); + float dx = fac * BLI_rctf_size_x(&v2d->cur) / 10.0f; if (event->type == MOUSEPAN) { fac = 0.01f * (event->prevy - event->y); } - dy = fac * BLI_rctf_size_y(&v2d->cur) / 10.0f; + float dy = fac * BLI_rctf_size_y(&v2d->cur) / 10.0f; /* support trackpad zoom to always zoom entirely - the v2d code uses portrait or * landscape exceptions */ @@ -1491,11 +1476,11 @@ static int view_borderzoom_exec(bContext *C, wmOperator *op) { ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; - rctf rect; rctf cur_new = v2d->cur; const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* convert coordinates of rect to 'tot' rect coordinates */ + rctf rect; WM_operator_properties_border_to_rctf(op, &rect); UI_view2d_region_to_view_rctf(v2d, &rect, &rect); @@ -1766,13 +1751,13 @@ static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; struct SmoothView2DStore *sms = v2d->sms; - float step; /* escape if not our timer */ if (v2d->smooth_timer == NULL || v2d->smooth_timer != event->customdata) { return OPERATOR_PASS_THROUGH; } + float step; if (sms->time_allowed != 0.0) { step = (float)((v2d->smooth_timer->duration) / sms->time_allowed); } @@ -1978,15 +1963,11 @@ static void scroller_activate_init(bContext *C, const wmEvent *event, const char in_scroller) { - v2dScrollerMove *vsm; - View2DScrollers scrollers; ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; - rctf tot_cur_union; - float mask_size; /* set custom-data for operator */ - vsm = MEM_callocN(sizeof(v2dScrollerMove), "v2dScrollerMove"); + v2dScrollerMove *vsm = MEM_callocN(sizeof(v2dScrollerMove), "v2dScrollerMove"); op->customdata = vsm; /* set general data */ @@ -2000,16 +1981,17 @@ static void scroller_activate_init(bContext *C, /* 'zone' depends on where mouse is relative to bubble * - zooming must be allowed on this axis, otherwise, default to pan */ + View2DScrollers scrollers; UI_view2d_scrollers_calc(v2d, NULL, &scrollers); /* Use a union of 'cur' & 'tot' in case the current view is far outside 'tot'. In this cases * moving the scroll bars has far too little effect and the view can get stuck T31476. */ - tot_cur_union = v2d->tot; + rctf tot_cur_union = v2d->tot; BLI_rctf_union(&tot_cur_union, &v2d->cur); if (in_scroller == 'h') { /* horizontal scroller - calculate adjustment factor first */ - mask_size = (float)BLI_rcti_size_x(&v2d->hor); + float mask_size = (float)BLI_rcti_size_x(&v2d->hor); vsm->fac = BLI_rctf_size_x(&tot_cur_union) / mask_size; /* pixel rounding */ @@ -2029,7 +2011,7 @@ static void scroller_activate_init(bContext *C, } else { /* vertical scroller - calculate adjustment factor first */ - mask_size = (float)BLI_rcti_size_y(&v2d->vert); + float mask_size = (float)BLI_rcti_size_y(&v2d->vert); vsm->fac = BLI_rctf_size_y(&tot_cur_union) / mask_size; /* pixel rounding */ @@ -2076,10 +2058,9 @@ static void scroller_activate_apply(bContext *C, wmOperator *op) { v2dScrollerMove *vsm = op->customdata; View2D *v2d = vsm->v2d; - float temp; /* calculate amount to move view by */ - temp = vsm->fac * vsm->delta; + float temp = vsm->fac * vsm->delta; /* round to pixel */ temp = roundf(temp / vsm->fac_round) * vsm->fac_round; @@ -2219,11 +2200,9 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent * /* if in a scroller, init customdata then set modal handler which will * catch mouse-down to start doing useful stuff */ if (in_scroller) { - v2dScrollerMove *vsm; - /* initialize customdata */ scroller_activate_init(C, op, event, in_scroller); - vsm = (v2dScrollerMove *)op->customdata; + v2dScrollerMove *vsm = (v2dScrollerMove *)op->customdata; /* support for quick jump to location - gtk and qt do this on linux */ if (event->type == MIDDLEMOUSE) { @@ -2324,12 +2303,11 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op)) const uiStyle *style = UI_style_get(); ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; - int winx, winy; const int snap_test = ED_region_snap_size_test(region); /* zoom 1.0 */ - winx = (float)(BLI_rcti_size_x(&v2d->mask) + 1); - winy = (float)(BLI_rcti_size_y(&v2d->mask) + 1); + const int winx = (float)(BLI_rcti_size_x(&v2d->mask) + 1); + const int winy = (float)(BLI_rcti_size_y(&v2d->mask) + 1); v2d->cur.xmax = v2d->cur.xmin + winx; v2d->cur.ymax = v2d->cur.ymin + winy; diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index b8badd207fe..e788b28d3b4 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -1129,7 +1129,7 @@ void MESH_OT_bevel(wmOperatorType *ot) prop_affect_items, BEVEL_AFFECT_EDGES, "Affect", - "Affect Edges or Vertices"); + "Affect edges or vertices"); RNA_def_boolean(ot->srna, "clamp_overlap", diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index ef78d31a6bb..aa144dd3f3c 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -177,6 +177,6 @@ void MESH_OT_knife_project(wmOperatorType *ot) RNA_def_boolean(ot->srna, "cut_through", false, - "Cut through", + "Cut Through", "Cut through all faces, not just visible ones"); } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index a2fe949b6c5..d3eaa9048d3 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -4552,7 +4552,8 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) /* edges */ RNA_def_boolean(ot->srna, "use_wire", true, "Wire", "Wire edges"); RNA_def_boolean(ot->srna, "use_boundary", true, "Boundaries", "Boundary edges"); - RNA_def_boolean(ot->srna, "use_multi_face", true, "Multiple Faces", "Edges shared by 3+ faces"); + RNA_def_boolean( + ot->srna, "use_multi_face", true, "Multiple Faces", "Edges shared by more than two faces"); RNA_def_boolean(ot->srna, "use_non_contiguous", true, diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index 00349983c57..d762eede079 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -34,6 +34,7 @@ #include "BKE_material.h" #include "BKE_report.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "WM_api.h" diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index aab17d6da61..59ce9140ab8 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -180,7 +180,7 @@ void MESH_OT_subdivide(wmOperatorType *ot) "ngon", true, "Create N-Gons", - "When disabled, newly created faces are limited to 3-4 sided faces"); + "When disabled, newly created faces are limited to 3 and 4 sided faces"); RNA_def_enum( ot->srna, "quadcorner", @@ -395,7 +395,7 @@ void MESH_OT_unsubdivide(wmOperatorType *ot) { /* identifiers */ ot->name = "Un-Subdivide"; - ot->description = "UnSubdivide selected edges & faces"; + ot->description = "Un-subdivide selected edges and faces"; ot->idname = "MESH_OT_unsubdivide"; /* api callbacks */ @@ -698,7 +698,7 @@ void MESH_OT_edge_collapse(wmOperatorType *ot) /* identifiers */ ot->name = "Collapse Edges & Faces"; ot->description = - "Collapse isolated edges & faces regions, merging data such as UV's and vertex colors. " + "Collapse isolated edge and face regions, merging data such as UV's and vertex colors. " "This can collapse edge-rings as well as regions of connected faces into vertices"; ot->idname = "MESH_OT_edge_collapse"; @@ -1904,7 +1904,7 @@ void MESH_OT_edge_split(wmOperatorType *ot) "VERT", 0, "Faces & Edges by Vertices", - "Split faces & edges connected to selected vertices"}, + "Split faces and edges connected to selected vertices"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 99f7992c2a9..b16b2809e51 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -27,6 +27,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BLI_array_utils.h" #include "BLI_listbase.h" diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 138e394a4d8..ce77f90c5fe 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1140,8 +1140,10 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, if (use_topology) { v_mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, i); - if (respecthide && BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) { - v_mirr = NULL; + if (v_mirr != NULL) { + if (respecthide && BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) { + v_mirr = NULL; + } } } else { diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c index 552e459acb1..b4030ad269b 100644 --- a/source/blender/editors/metaball/editmball_undo.c +++ b/source/blender/editors/metaball/editmball_undo.c @@ -30,8 +30,10 @@ #include "BLI_utildefines.h" #include "DNA_defs.h" +#include "DNA_layer_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BKE_context.h" #include "BKE_layer.h" diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index a1be9b9df61..77b5379ddd4 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -31,8 +31,8 @@ set(INC ../../makesrna ../../modifiers ../../python - ../../shader_fx ../../render + ../../shader_fx ../../windowmanager ../../../../intern/clog ../../../../intern/glew-mx @@ -88,6 +88,7 @@ endif() if(WITH_EXPERIMENTAL_FEATURES) add_definitions(-DWITH_GEOMETRY_NODES) + add_definitions(-DWITH_POINT_CLOUD) add_definitions(-DWITH_HAIR_NODES) endif() diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 4e0f6211c18..a64033bc63a 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1618,6 +1618,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } Object *ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, local_view_bits); + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ob); /* to make it easier to start using this immediately in NLA, a default sound clip is created * ready to be moved around to retime the sound and/or make new sound clips @@ -1625,13 +1626,13 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op) { /* create new data for NLA hierarchy */ AnimData *adt = BKE_animdata_add_id(&ob->id); - NlaTrack *nlt = BKE_nlatrack_add(adt, NULL); + NlaTrack *nlt = BKE_nlatrack_add(adt, NULL, is_liboverride); NlaStrip *strip = BKE_nla_add_soundstrip(bmain, scene, ob->data); strip->start = CFRA; strip->end += strip->start; /* hook them up */ - BKE_nlatrack_add_strip(nlt, strip); + BKE_nlatrack_add_strip(nlt, strip, is_liboverride); /* auto-name the strip, and give the track an interesting name */ BLI_strncpy(nlt->name, DATA_("SoundTrack"), sizeof(nlt->name)); @@ -1713,6 +1714,9 @@ void OBJECT_OT_hair_add(wmOperatorType *ot) static bool object_pointcloud_add_poll(bContext *C) { + if (!U.experimental.use_new_point_cloud_type) { + return false; + } return ED_operator_objectmode(C); } @@ -2315,17 +2319,23 @@ static const EnumPropertyItem convert_target_items[] = { "MESH", ICON_OUTLINER_OB_MESH, "Mesh", +#ifdef WITH_POINT_CLOUD "Mesh from Curve, Surface, Metaball, Text, or Pointcloud objects"}, +#else + "Mesh from Curve, Surface, Metaball, or Text objects"}, +#endif {OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil", "Grease Pencil from Curve or Mesh objects"}, +#ifdef WITH_POINT_CLOUD {OB_POINTCLOUD, "POINTCLOUD", ICON_OUTLINER_OB_POINTCLOUD, "Pointcloud", "Pointcloud from Mesh objects"}, +#endif {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 008498a1735..9618774eea8 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -25,6 +25,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index e684ad03f53..dd015f59e8d 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -706,8 +706,9 @@ static bool edit_constraint_poll_generic(bContext *C, return false; } - if (!is_liboverride_allowed && !BKE_constraint_is_local_in_liboverride(ob, con)) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit constraints coming from library override"); + if (!is_liboverride_allowed && BKE_constraint_is_nonlocal_in_liboverride(ob, con)) { + CTX_wm_operator_poll_msg_set( + C, "Cannot edit constraints coming from linked data in a library override"); return false; } diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c index d3f165678c3..e5feb74df26 100644 --- a/source/blender/editors/object/object_gpencil_modifier.c +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -443,9 +443,9 @@ static bool gpencil_edit_modifier_poll_generic(bContext *C, return false; } - if (!is_liboverride_allowed && - (mod == NULL || !BKE_gpencil_modifier_is_local_in_liboverride(ob, mod))) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override"); + if (!is_liboverride_allowed && BKE_gpencil_modifier_is_nonlocal_in_liboverride(ob, mod)) { + CTX_wm_operator_poll_msg_set( + C, "Cannot edit modifiers coming from linked data in a library override"); return false; } @@ -461,7 +461,7 @@ static bool gpencil_edit_modifier_poll(bContext *C) * (not only from added 'local' ones). */ static bool gpencil_edit_modifier_liboverride_allowed_poll(bContext *C) { - return gpencil_edit_modifier_poll_generic(C, &RNA_Modifier, 0, true); + return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0, true); } static void gpencil_edit_modifier_properties(wmOperatorType *ot) @@ -789,7 +789,7 @@ void OBJECT_OT_gpencil_modifier_apply(wmOperatorType *ot) "apply_as", gpencil_modifier_apply_as_items, MODIFIER_APPLY_DATA, - "Apply as", + "Apply As", "How to apply the modifier to the geometry"); gpencil_edit_modifier_properties(ot); gpencil_edit_modifier_report_property(ot); diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index e6ef53a3d65..89ade5cc49d 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -206,6 +206,7 @@ void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot); /* object_shader_fx.c */ void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot); +void OBJECT_OT_shaderfx_copy(struct wmOperatorType *ot); void OBJECT_OT_shaderfx_remove(struct wmOperatorType *ot); void OBJECT_OT_shaderfx_move_up(struct wmOperatorType *ot); void OBJECT_OT_shaderfx_move_down(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index bb4581b0ee8..3111003703f 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -1052,8 +1052,9 @@ bool edit_modifier_poll_generic(bContext *C, return false; } - if (!is_liboverride_allowed && !BKE_modifier_is_local_in_liboverride(ob, mod)) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override"); + if (!is_liboverride_allowed && BKE_modifier_is_nonlocal_in_liboverride(ob, mod)) { + CTX_wm_operator_poll_msg_set( + C, "Cannot edit modifiers coming from linked data in a library override"); return false; } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 8ba0ce5fd08..2e5a75ffa7d 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -166,6 +166,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_shaderfx_move_up); WM_operatortype_append(OBJECT_OT_shaderfx_move_down); WM_operatortype_append(OBJECT_OT_shaderfx_move_to_index); + WM_operatortype_append(OBJECT_OT_shaderfx_copy); WM_operatortype_append(OBJECT_OT_correctivesmooth_bind); WM_operatortype_append(OBJECT_OT_meshdeform_bind); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 8841b1955bf..ee9ef192d18 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -484,7 +484,7 @@ void OBJECT_OT_proxy_make(wmOperatorType *ot) DummyRNA_DEFAULT_items, 0, "Proxy Object", - "Name of lib-linked/collection object to make a proxy for"); + "Name of library-linked/collection object to make a proxy for"); RNA_def_enum_funcs(prop, proxy_collection_object_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; @@ -1554,6 +1554,7 @@ enum { MAKE_LINKS_DUPLICOLLECTION = 5, MAKE_LINKS_MODIFIERS = 6, MAKE_LINKS_FONTS = 7, + MAKE_LINKS_SHADERFX = 8, }; /* Return true if make link data is allowed, false otherwise */ @@ -1589,6 +1590,11 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst return true; } break; + case MAKE_LINKS_SHADERFX: + if ((ob_src->type == OB_GPENCIL) && (ob_dst->type == OB_GPENCIL)) { + return true; + } + break; } return false; } @@ -1720,6 +1726,11 @@ static int make_links_data_exec(bContext *C, wmOperator *op) ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); break; } + case MAKE_LINKS_SHADERFX: + ED_object_shaderfx_link(ob_dst, ob_src); + DEG_id_tag_update(&ob_dst->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + break; } } } @@ -1782,6 +1793,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) {MAKE_LINKS_DUPLICOLLECTION, "DUPLICOLLECTION", 0, "Instance Collection", ""}, {MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Modifiers", ""}, {MAKE_LINKS_FONTS, "FONTS", 0, "Fonts", ""}, + {MAKE_LINKS_SHADERFX, "EFFECTS", 0, "Effects", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -2515,7 +2527,7 @@ static bool convert_proxy_to_override_poll(bContext *C) return obact != NULL && obact->proxy != NULL; } -static int convert_proxy_to_override_exec(bContext *C, wmOperator *UNUSED(op)) +static int convert_proxy_to_override_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -2529,6 +2541,15 @@ static int convert_proxy_to_override_exec(bContext *C, wmOperator *UNUSED(op)) const bool success = BKE_lib_override_library_proxy_convert(bmain, scene, view_layer, ob_proxy); + if (!success) { + BKE_reportf( + op->reports, + RPT_ERROR_INVALID_INPUT, + "Could not create a library override from proxy '%s' (might use already local data?)", + ob_proxy->id.name + 2); + return OPERATOR_CANCELLED; + } + /* Remove the instance empty from this scene, the items now have an overridden collection * instead. */ if (success && is_override_instancing_object) { @@ -2544,7 +2565,7 @@ static int convert_proxy_to_override_exec(bContext *C, wmOperator *UNUSED(op)) void OBJECT_OT_convert_proxy_to_override(wmOperatorType *ot) { /* identifiers */ - ot->name = "Convert Proxy To Override"; + ot->name = "Convert Proxy to Override"; ot->description = "Convert a proxy to a local library override"; ot->idname = "OBJECT_OT_convert_proxy_to_override"; diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c index c5caee5ba08..2b1ac08ec2e 100644 --- a/source/blender/editors/object/object_shader_fx.c +++ b/source/blender/editors/object/object_shader_fx.c @@ -640,3 +640,57 @@ void OBJECT_OT_shaderfx_move_to_index(wmOperatorType *ot) RNA_def_int( ot->srna, "index", 0, 0, INT_MAX, "Index", "The index to move the effect to", 0, INT_MAX); } + +/************************ copy shader operator *********************/ + +static int shaderfx_copy_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); + + ShaderFxData *nfx = BKE_shaderfx_new(fx->type); + if (!nfx) { + return OPERATOR_CANCELLED; + } + + BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name)); + /* Make sure effect data has unique name. */ + BKE_shaderfx_unique_name(&ob->shader_fx, nfx); + + BKE_shaderfx_copydata(fx, nfx); + BLI_insertlinkafter(&ob->shader_fx, fx, nfx); + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_OBJECT | ND_SHADERFX, ob); + + return OPERATOR_FINISHED; +} + +static int shaderfx_copy_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int retval; + if (edit_shaderfx_invoke_properties(C, op, event, &retval)) { + return shaderfx_copy_exec(C, op); + } + return retval; +} + +static bool shaderfx_copy_poll(bContext *C) +{ + return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0); +} + +void OBJECT_OT_shaderfx_copy(wmOperatorType *ot) +{ + ot->name = "Copy Effect"; + ot->description = "Duplicate effect at the same position in the stack"; + ot->idname = "OBJECT_OT_shaderfx_copy"; + + ot->invoke = shaderfx_copy_invoke; + ot->exec = shaderfx_copy_exec; + ot->poll = shaderfx_copy_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_shaderfx_properties(ot); +} diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 3d6a6abfe0d..fc4969019b5 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -736,14 +736,19 @@ const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext * RNA_enum_items_add_value(&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_ACTIVE); } - if (BKE_object_pose_armature_get(ob)) { - if (selection_mask & (1 << WT_VGROUP_BONE_SELECT)) { - RNA_enum_items_add_value( - &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_SELECT); + if (ob) { + if (BKE_object_pose_armature_get(ob)) { + if (selection_mask & (1 << WT_VGROUP_BONE_SELECT)) { + RNA_enum_items_add_value( + &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_SELECT); + } } - if (selection_mask & (1 << WT_VGROUP_BONE_DEFORM)) { - RNA_enum_items_add_value( - &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_DEFORM); + + if (BKE_modifiers_is_deformed_by_armature(ob)) { + if (selection_mask & (1 << WT_VGROUP_BONE_DEFORM)) { + RNA_enum_items_add_value( + &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_DEFORM); + } } } diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 017cd63d9d5..f5c3fc17552 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -1203,6 +1203,9 @@ static bool copy_particle_systems_to_object(const bContext *C, #undef PSYS_FROM_FIRST #undef PSYS_FROM_NEXT + if (duplicate_settings) { + DEG_relations_tag_update(bmain); + } DEG_id_tag_update(&ob_to->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to); return true; diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c index 4939bf0086b..cb7ca5bd5d1 100644 --- a/source/blender/editors/physics/rigidbody_constraint.c +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -25,6 +25,7 @@ #include <stdlib.h> #include <string.h> +#include "DNA_collection_types.h" #include "DNA_object_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index cb25363d2b2..4fd304ea71d 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -25,6 +25,7 @@ #include <stdlib.h> #include <string.h> +#include "DNA_collection_types.h" #include "DNA_object_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h index e1d03e6f3be..e60455667e9 100644 --- a/source/blender/editors/render/render_intern.h +++ b/source/blender/editors/render/render_intern.h @@ -38,8 +38,11 @@ void OBJECT_OT_material_slot_move(struct wmOperatorType *ot); void OBJECT_OT_material_slot_remove_unused(struct wmOperatorType *ot); void MATERIAL_OT_new(struct wmOperatorType *ot); +void MATERIAL_OT_duplicate(struct wmOperatorType *ot); void TEXTURE_OT_new(struct wmOperatorType *ot); +void TEXTURE_OT_duplicate(struct wmOperatorType *ot); void WORLD_OT_new(struct wmOperatorType *ot); +void WORLD_OT_duplicate(struct wmOperatorType *ot); void MATERIAL_OT_copy(struct wmOperatorType *ot); void MATERIAL_OT_paste(struct wmOperatorType *ot); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 3dbf70aa4bc..10cf4131584 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -29,6 +29,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_rect.h" #include "BLI_threads.h" #include "BLI_timecode.h" #include "BLI_utildefines.h" @@ -82,7 +83,7 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "SEQ_sequencer.h" +#include "SEQ_relations.h" #include "BLO_undofile.h" @@ -121,72 +122,90 @@ typedef struct RenderJob { } RenderJob; /* called inside thread! */ -static void image_buffer_rect_update(RenderJob *rj, - RenderResult *rr, - ImBuf *ibuf, - ImageUser *iuser, - volatile rcti *renrect, - const char *viewname) +static bool image_buffer_calc_tile_rect(const RenderResult *rr, + const ImBuf *ibuf, + volatile rcti *renrect, + rcti *r_ibuf_rect, + int *r_offset_x, + int *r_offset_y) { - Scene *scene = rj->scene; - const float *rectf = NULL; - int ymin, ymax, xmin, xmax; - int rymin, rxmin; - int linear_stride, linear_offset_x, linear_offset_y; - ColorManagedViewSettings *view_settings; - ColorManagedDisplaySettings *display_settings; - - if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) { - /* The whole image buffer it so be color managed again anyway. */ - return; - } + int tile_y, tile_height, tile_x, tile_width; /* if renrect argument, we only refresh scanlines */ if (renrect) { - /* if (ymax == recty), rendering of layer is ready, + /* if (tile_height == recty), rendering of layer is ready, * we should not draw, other things happen... */ if (rr->renlay == NULL || renrect->ymax >= rr->recty) { - return; + return false; } - /* xmin here is first subrect x coord, xmax defines subrect width */ - xmin = renrect->xmin + rr->crop; - xmax = renrect->xmax - xmin + rr->crop; - if (xmax < 2) { - return; + /* tile_x here is first subrect x coord, tile_width defines subrect width */ + tile_x = renrect->xmin; + tile_width = renrect->xmax - tile_x; + if (tile_width < 2) { + return false; } - ymin = renrect->ymin + rr->crop; - ymax = renrect->ymax - ymin + rr->crop; - if (ymax < 2) { - return; + tile_y = renrect->ymin; + tile_height = renrect->ymax - tile_y; + if (tile_height < 2) { + return false; } renrect->ymin = renrect->ymax; } else { - xmin = ymin = rr->crop; - xmax = rr->rectx - 2 * rr->crop; - ymax = rr->recty - 2 * rr->crop; + tile_x = tile_y = 0; + tile_width = rr->rectx; + tile_height = rr->recty; } - /* xmin ymin is in tile coords. transform to ibuf */ - rxmin = rr->tilerect.xmin + xmin; - if (rxmin >= ibuf->x) { - return; + /* tile_x tile_y is in tile coords. transform to ibuf */ + int offset_x = rr->tilerect.xmin; + if (offset_x >= ibuf->x) { + return false; } - rymin = rr->tilerect.ymin + ymin; - if (rymin >= ibuf->y) { - return; + int offset_y = rr->tilerect.ymin; + if (offset_y >= ibuf->y) { + return false; } - if (rxmin + xmax > ibuf->x) { - xmax = ibuf->x - rxmin; + if (offset_x + tile_width > ibuf->x) { + tile_width = ibuf->x - offset_x; } - if (rymin + ymax > ibuf->y) { - ymax = ibuf->y - rymin; + if (offset_y + tile_height > ibuf->y) { + tile_height = ibuf->y - offset_y; } - if (xmax < 1 || ymax < 1) { + if (tile_width < 1 || tile_height < 1) { + return false; + } + + r_ibuf_rect->xmax = tile_x + tile_width; + r_ibuf_rect->ymax = tile_y + tile_height; + r_ibuf_rect->xmin = tile_x; + r_ibuf_rect->ymin = tile_y; + *r_offset_x = offset_x; + *r_offset_y = offset_y; + return true; +} + +static void image_buffer_rect_update(RenderJob *rj, + RenderResult *rr, + ImBuf *ibuf, + ImageUser *iuser, + const rcti *tile_rect, + int offset_x, + int offset_y, + const char *viewname) +{ + Scene *scene = rj->scene; + const float *rectf = NULL; + int linear_stride, linear_offset_x, linear_offset_y; + ColorManagedViewSettings *view_settings; + ColorManagedDisplaySettings *display_settings; + + if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) { + /* The whole image buffer is to be color managed again anyway. */ return; } @@ -230,10 +249,10 @@ static void image_buffer_rect_update(RenderJob *rj, return; } - rectf += 4 * (rr->rectx * ymin + xmin); + rectf += 4 * (rr->rectx * tile_rect->ymin + tile_rect->xmin); linear_stride = rr->rectx; - linear_offset_x = rxmin; - linear_offset_y = rymin; + linear_offset_x = offset_x; + linear_offset_y = offset_y; } else { rectf = ibuf->rect_float; @@ -253,10 +272,10 @@ static void image_buffer_rect_update(RenderJob *rj, linear_offset_y, view_settings, display_settings, - rxmin, - rymin, - rxmin + xmax, - rymin + ymax); + offset_x, + offset_y, + offset_x + BLI_rcti_size_x(tile_rect), + offset_y + BLI_rcti_size_y(tile_rect)); } /* ****************************** render invoking ***************** */ @@ -344,7 +363,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) * otherwise, invalidated cache entries can make their way into * the output rendering. We can't put that into RE_RenderFrame, * since sequence rendering can call that recursively... (peter) */ - BKE_sequencer_cache_cleanup(scene); + SEQ_cache_cleanup(scene); RE_SetReports(re, op->reports); @@ -578,8 +597,16 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec /* update part of render */ render_image_update_pass_and_layer(rj, rr, &rj->iuser); + rcti tile_rect; + int offset_x; + int offset_y; ibuf = BKE_image_acquire_ibuf(ima, &rj->iuser, &lock); if (ibuf) { + if (!image_buffer_calc_tile_rect(rr, ibuf, renrect, &tile_rect, &offset_x, &offset_y)) { + BKE_image_release_ibuf(ima, ibuf, lock); + return; + } + /* Don't waste time on CPU side color management if * image will be displayed using GLSL. * @@ -589,9 +616,10 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec */ if (!rj->supports_glsl_draw || ibuf->channels == 1 || ED_draw_imbuf_method(ibuf) != IMAGE_DRAW_METHOD_GLSL) { - image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect, viewname); + image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, &tile_rect, offset_x, offset_y, viewname); } - ima->gpuflag |= IMA_GPU_REFRESH; + BKE_image_update_gputexture_delayed( + ima, ibuf, offset_x, offset_y, BLI_rcti_size_x(&tile_rect), BLI_rcti_size_y(&tile_rect)); /* make jobs timer to send notifier */ *(rj->do_update) = true; @@ -907,7 +935,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* Reports are done inside check function, and it will return false if there are other strips to * render. */ - if ((scene->r.scemode & R_DOSEQ) && BKE_sequencer_check_scene_recursion(scene, op->reports)) { + if ((scene->r.scemode & R_DOSEQ) && SEQ_relations_check_scene_recursion(scene, op->reports)) { return OPERATOR_CANCELLED; } @@ -929,7 +957,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even * otherwise, invalidated cache entries can make their way into * the output rendering. We can't put that into RE_RenderFrame, * since sequence rendering can call that recursively... (peter) */ - BKE_sequencer_cache_cleanup(scene); + SEQ_cache_cleanup(scene); /* store spare * get view3d layer, local layer, make this nice api call to render diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index f7275b06804..1069f942a7a 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -77,7 +77,7 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "SEQ_sequencer.h" +#include "SEQ_render.h" #include "GPU_framebuffer.h" #include "GPU_matrix.h" diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c index e0aa02b354d..48e894036d9 100644 --- a/source/blender/editors/render/render_ops.c +++ b/source/blender/editors/render/render_ops.c @@ -45,8 +45,11 @@ void ED_operatortypes_render(void) WM_operatortype_append(OBJECT_OT_material_slot_remove_unused); WM_operatortype_append(MATERIAL_OT_new); + WM_operatortype_append(MATERIAL_OT_duplicate); WM_operatortype_append(TEXTURE_OT_new); + WM_operatortype_append(TEXTURE_OT_duplicate); WM_operatortype_append(WORLD_OT_new); + WM_operatortype_append(WORLD_OT_duplicate); WM_operatortype_append(MATERIAL_OT_copy); WM_operatortype_append(MATERIAL_OT_paste); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 095deccada0..579fd86077e 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -68,6 +68,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" +#include "BKE_object.h" #include "BKE_scene.h" #include "BKE_texture.h" #include "BKE_world.h" @@ -94,12 +95,16 @@ #include "ED_datafiles.h" #include "ED_render.h" #include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_view3d_offscreen.h" #ifndef NDEBUG /* Used for database init assert(). */ # include "BLI_threads.h" #endif +static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect); + ImBuf *get_brush_icon(Brush *brush) { static const int flags = IB_rect | IB_multilayer | IB_metadata; @@ -184,7 +189,7 @@ typedef struct IconPreview { Main *bmain; Scene *scene; void *owner; - ID *id, *id_copy; + ID *id, *id_copy; /* May be NULL! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */ ListBase sizes; } IconPreview; @@ -336,7 +341,7 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world) return sp->worldcopy; } -static ID *duplicate_ids(ID *id) +static ID *duplicate_ids(ID *id, const bool allow_failure) { if (id == NULL) { /* Non-ID preview render. */ @@ -344,20 +349,25 @@ static ID *duplicate_ids(ID *id) } switch (GS(id->name)) { + case ID_OB: case ID_MA: case ID_TE: case ID_LA: case ID_WO: { + BLI_assert(BKE_previewimg_id_supports_jobs(id)); ID *id_copy = BKE_id_copy_ex( NULL, id, NULL, LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA); return id_copy; } + /* These support threading, but don't need duplicating. */ case ID_IM: case ID_BR: - case ID_SCR: + BLI_assert(BKE_previewimg_id_supports_jobs(id)); return NULL; default: - BLI_assert(!"ID type preview not supported."); + if (!allow_failure) { + BLI_assert(!"ID type preview not supported."); + } return NULL; } } @@ -698,6 +708,132 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r } } +/* **************************** Object preview ****************** */ + +struct ObjectPreviewData { + /* The main for the preview, not of the current file. */ + Main *pr_main; + /* Copy of the object to create the preview for. The copy is for thread safety (and to insert it + * into an own main). */ + Object *object; + int sizex; + int sizey; +}; + +static Object *object_preview_camera_create( + Main *preview_main, ViewLayer *view_layer, Object *preview_object, int sizex, int sizey) +{ + Object *camera = BKE_object_add(preview_main, view_layer, OB_CAMERA, "Preview Camera"); + + float rotmat[3][3]; + float dummyscale[3]; + mat4_to_loc_rot_size(camera->loc, rotmat, dummyscale, preview_object->obmat); + + /* Camera is Y up, so needs additional 90deg rotation around X to match object's Z up. */ + float drotmat[3][3]; + axis_angle_to_mat3_single(drotmat, 'X', M_PI_2); + mul_m3_m3_post(rotmat, drotmat); + + camera->rotmode = ROT_MODE_QUAT; + mat3_to_quat(camera->quat, rotmat); + + /* shader_preview_render() does this too. */ + if (sizex > sizey) { + ((Camera *)camera->data)->lens *= (float)sizey / (float)sizex; + } + + return camera; +} + +static Scene *object_preview_scene_create(const struct ObjectPreviewData *preview_data, + Depsgraph **r_depsgraph) +{ + Scene *scene = BKE_scene_add(preview_data->pr_main, "Object preview scene"); + ViewLayer *view_layer = scene->view_layers.first; + Depsgraph *depsgraph = DEG_graph_new( + preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT); + + BLI_assert(preview_data->object != NULL); + BLI_addtail(&preview_data->pr_main->objects, preview_data->object); + + BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object); + + Object *camera_object = object_preview_camera_create(preview_data->pr_main, + view_layer, + preview_data->object, + preview_data->sizex, + preview_data->sizey); + + scene->camera = camera_object; + scene->r.xsch = preview_data->sizex; + scene->r.ysch = preview_data->sizey; + scene->r.size = 100; + + Base *preview_base = BKE_view_layer_base_find(view_layer, preview_data->object); + /* For 'view selected' below. */ + preview_base->flag |= BASE_SELECTED; + + DEG_graph_build_from_view_layer(depsgraph); + DEG_evaluate_on_refresh(depsgraph); + + ED_view3d_camera_to_view_selected(preview_data->pr_main, depsgraph, scene, camera_object); + + BKE_scene_graph_update_tagged(depsgraph, preview_data->pr_main); + + *r_depsgraph = depsgraph; + return scene; +} + +static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized) +{ + Main *preview_main = BKE_main_new(); + const float pixelsize_old = U.pixelsize; + char err_out[256] = "unknown"; + + BLI_assert(preview->id_copy && (preview->id_copy != preview->id)); + + struct ObjectPreviewData preview_data = { + .pr_main = preview_main, + /* Act on a copy. */ + .object = (Object *)preview->id_copy, + .sizex = preview_sized->sizex, + .sizey = preview_sized->sizey, + }; + Depsgraph *depsgraph; + Scene *scene = object_preview_scene_create(&preview_data, &depsgraph); + + /* Ownership is now ours. */ + preview->id_copy = NULL; + + U.pixelsize = 2.0f; + + ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple( + depsgraph, + DEG_get_evaluated_scene(depsgraph), + NULL, + OB_SOLID, + DEG_get_evaluated_object(depsgraph, scene->camera), + preview_sized->sizex, + preview_sized->sizey, + IB_rect, + V3D_OFSDRAW_NONE, + R_ALPHAPREMUL, + NULL, + NULL, + err_out); + /* TODO color-management? */ + + U.pixelsize = pixelsize_old; + + if (ibuf) { + icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect); + IMB_freeImBuf(ibuf); + } + + DEG_graph_free(depsgraph); + BKE_main_free(preview_main); +} + /* **************************** new shader preview system ****************** */ /* inside thread, called by renderer, sets job update value */ @@ -1101,6 +1237,8 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat ID *id = sp->id; short idtype = GS(id->name); + BLI_assert(id != NULL); + if (idtype == ID_IM) { Image *ima = (Image *)id; ImBuf *ibuf = NULL; @@ -1188,27 +1326,72 @@ static void common_preview_startjob(void *customdata, } } -/* exported functions */ - -static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey) +/** + * Some ID types already have their own, more focused rendering (only objects right now). This is + * for the other ones, which all share #ShaderPreview and some functions. + */ +static void other_id_types_preview_render(IconPreview *ip, + IconPreviewSize *cur_size, + const bool is_deferred, + short *stop, + short *do_update, + float *progress) { - IconPreviewSize *cur_size = ip->sizes.first, *new_size; + ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview"); + const bool is_render = !is_deferred; + + /* These types don't use the ShaderPreview mess, they have their own types and functions. */ + BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB)); + + /* construct shader preview from image size and previewcustomdata */ + sp->scene = ip->scene; + sp->owner = ip->owner; + sp->sizex = cur_size->sizex; + sp->sizey = cur_size->sizey; + sp->pr_method = is_render ? PR_ICON_RENDER : PR_ICON_DEFERRED; + sp->pr_rect = cur_size->rect; + sp->id = ip->id; + sp->id_copy = ip->id_copy; + sp->bmain = ip->bmain; + sp->own_id_copy = false; + Material *ma = NULL; - while (cur_size) { - if (cur_size->sizex == sizex && cur_size->sizey == sizey) { - /* requested size is already in list, no need to add it again */ - return; + if (is_render) { + BLI_assert(ip->id); + + /* grease pencil use its own preview file */ + if (GS(ip->id->name) == ID_MA) { + ma = (Material *)ip->id; } - cur_size = cur_size->next; + if ((ma == NULL) || (ma->gp_style == NULL)) { + sp->pr_main = G_pr_main; + } + else { + sp->pr_main = G_pr_main_grease_pencil; + } } - new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize"); - new_size->sizex = sizex; - new_size->sizey = sizey; - new_size->rect = rect; + common_preview_startjob(sp, stop, do_update, progress); + shader_preview_free(sp); +} - BLI_addtail(&ip->sizes, new_size); +/* exported functions */ + +/** + * Find the index to map \a icon_size to data in \a preview_image. + */ +static int icon_previewimg_size_index_get(const IconPreviewSize *icon_size, + const PreviewImage *preview_image) +{ + for (int i = 0; i < NUM_ICON_SIZES; i++) { + if ((preview_image->w[i] == icon_size->sizex) && (preview_image->h[i] == icon_size->sizey)) { + return i; + } + } + + BLI_assert(!"The searched icon size does not match any in the preview image"); + return -1; } static void icon_preview_startjob_all_sizes(void *customdata, @@ -1235,41 +1418,43 @@ static void icon_preview_startjob_all_sizes(void *customdata, continue; } - ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview"); - const bool is_render = !(prv->tag & PRV_TAG_DEFFERED); - - /* construct shader preview from image size and previewcustomdata */ - sp->scene = ip->scene; - sp->owner = ip->owner; - sp->sizex = cur_size->sizex; - sp->sizey = cur_size->sizey; - sp->pr_method = is_render ? PR_ICON_RENDER : PR_ICON_DEFERRED; - sp->pr_rect = cur_size->rect; - sp->id = ip->id; - sp->id_copy = ip->id_copy; - sp->bmain = ip->bmain; - sp->own_id_copy = false; - Material *ma = NULL; - - if (is_render) { - BLI_assert(ip->id); - - /* grease pencil use its own preview file */ - if (GS(ip->id->name) == ID_MA) { - ma = (Material *)ip->id; - } +#ifndef NDEBUG + { + int size_index = icon_previewimg_size_index_get(cur_size, prv); + BLI_assert(!BKE_previewimg_is_finished(prv, size_index)); + } +#endif - if ((ma == NULL) || (ma->gp_style == NULL)) { - sp->pr_main = G_pr_main; - } - else { - sp->pr_main = G_pr_main_grease_pencil; - } + if (ip->id && ELEM(GS(ip->id->name), ID_OB)) { + /* Much simpler than the ShaderPreview mess used for other ID types. */ + object_preview_render(ip, cur_size); + } + else { + other_id_types_preview_render( + ip, cur_size, (prv->tag & PRV_TAG_DEFFERED), stop, do_update, progress); + } + } +} + +static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey) +{ + IconPreviewSize *cur_size = ip->sizes.first, *new_size; + + while (cur_size) { + if (cur_size->sizex == sizex && cur_size->sizey == sizey) { + /* requested size is already in list, no need to add it again */ + return; } - common_preview_startjob(sp, stop, do_update, progress); - shader_preview_free(sp); + cur_size = cur_size->next; } + + new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize"); + new_size->sizex = sizex; + new_size->sizey = sizey; + new_size->rect = rect; + + BLI_addtail(&ip->sizes, new_size); } static void icon_preview_endjob(void *customdata) @@ -1302,9 +1487,15 @@ static void icon_preview_endjob(void *customdata) if (ip->owner) { PreviewImage *prv_img = ip->owner; prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING; + + LISTBASE_FOREACH (IconPreviewSize *, icon_size, &ip->sizes) { + int size_index = icon_previewimg_size_index_get(icon_size, prv_img); + BKE_previewimg_finish(prv_img, size_index); + } + if (prv_img->tag & PRV_TAG_DEFFERED_DELETE) { BLI_assert(prv_img->tag & PRV_TAG_DEFFERED); - BKE_previewimg_cached_release_pointer(prv_img); + BKE_previewimg_deferred_release(prv_img); } } } @@ -1333,7 +1524,9 @@ void ED_preview_icon_render(Main *bmain, Scene *scene, ID *id, uint *rect, int s ip.scene = scene; ip.owner = BKE_previewimg_id_ensure(id); ip.id = id; - ip.id_copy = duplicate_ids(id); + /* Control isn't given back to the caller until the preview is done. So we don't need to copy + * the ID to avoid thread races. */ + ip.id_copy = duplicate_ids(id, true); icon_preview_add_size(&ip, rect, sizex, sizey); @@ -1376,7 +1569,7 @@ void ED_preview_icon_job( ip->scene = CTX_data_scene(C); ip->owner = owner; ip->id = id; - ip->id_copy = duplicate_ids(id); + ip->id_copy = duplicate_ids(id, false); icon_preview_add_size(ip, rect, sizex, sizey); @@ -1416,6 +1609,8 @@ void ED_preview_shader_job(const bContext *C, Scene *scene = CTX_data_scene(C); short id_type = GS(id->name); + BLI_assert(BKE_previewimg_id_supports_jobs(id)); + /* Use workspace render only for buttons Window, * since the other previews are related to the datablock. */ @@ -1445,7 +1640,7 @@ void ED_preview_shader_job(const bContext *C, sp->sizey = sizey; sp->pr_method = method; sp->id = id; - sp->id_copy = duplicate_ids(id); + sp->id_copy = duplicate_ids(id, false); sp->own_id_copy = true; sp->parent = parent; sp->slot = slot; diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index b69337b1621..cac01bdc048 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -735,45 +735,40 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name New Material Operator +/** \name Create Material Operators * \{ */ -static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) +struct MaterialCreationData { + Object *ob; + PropertyPointerRNA pprop; +}; + +static void material_creation_data_init_from_UI_context(bContext *C, + struct MaterialCreationData *r_create_data) { - Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; - Main *bmain = CTX_data_main(C); - PointerRNA ptr, idptr; + PointerRNA ptr; PropertyRNA *prop; /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); - Object *ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL; + r_create_data->ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL; + r_create_data->pprop.ptr = ptr; + r_create_data->pprop.prop = prop; +} - /* add or copy material */ - if (ma) { - Material *new_ma = (Material *)BKE_id_copy_ex( - bmain, &ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); - ma = new_ma; - } - else { - const char *name = DATA_("Material"); - if (!(ob != NULL && ob->type == OB_GPENCIL)) { - ma = BKE_material_add(bmain, name); - } - else { - ma = BKE_gpencil_material_add(bmain, name); - } - ED_node_shader_default(C, &ma->id); - ma->use_nodes = true; - } +static void material_creation_assign(bContext *C, + Material *ma, + struct MaterialCreationData *create_data) +{ + Main *bmain = CTX_data_main(C); - if (prop) { - if (ob != NULL) { + if (create_data->pprop.prop) { + if (create_data->ob != NULL) { /* Add slot follows user-preferences for creating new slots, * RNA pointer assignment doesn't, see: T60014. */ - if (BKE_object_material_get_p(ob, ob->actcol) == NULL) { - BKE_object_material_slot_add(bmain, ob); + if (BKE_object_material_get_p(create_data->ob, create_data->ob->actcol) == NULL) { + BKE_object_material_slot_add(bmain, create_data->ob); } } @@ -781,10 +776,32 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) * pointer use also increases user, so this compensates it */ id_us_min(&ma->id); + PointerRNA idptr; RNA_id_pointer_create(&ma->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr, NULL); - RNA_property_update(C, &ptr, prop); + RNA_property_pointer_set(&create_data->pprop.ptr, create_data->pprop.prop, idptr, NULL); + RNA_property_update(C, &create_data->pprop.ptr, create_data->pprop.prop); + } +} + +static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + struct MaterialCreationData create_data; + + material_creation_data_init_from_UI_context(C, &create_data); + + const char *name = DATA_("Material"); + Material *ma; + if ((create_data.ob == NULL) || (create_data.ob->type != OB_GPENCIL)) { + ma = BKE_material_add(bmain, name); + } + else { + ma = BKE_gpencil_material_add(bmain, name); } + ED_node_shader_default(C, &ma->id); + ma->use_nodes = true; + + material_creation_assign(C, ma, &create_data); WM_event_add_notifier(C, NC_MATERIAL | NA_ADDED, ma); @@ -806,27 +823,57 @@ void MATERIAL_OT_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } -/** \} */ +static int duplicate_material_exec(bContext *C, wmOperator *op) +{ + Material *old_ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; + + if (!old_ma) { + BKE_report( + op->reports, + RPT_ERROR, + "Incorrect context for duplicating a material (did not find material to duplicate)"); + return OPERATOR_CANCELLED; + } + + Main *bmain = CTX_data_main(C); + struct MaterialCreationData create_data; + + material_creation_data_init_from_UI_context(C, &create_data); + + Material *new_ma = (Material *)BKE_id_copy_ex( + bmain, &old_ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); + + material_creation_assign(C, new_ma, &create_data); + + WM_event_add_notifier(C, NC_MATERIAL | NA_ADDED, new_ma); + + return OPERATOR_FINISHED; +} + +void MATERIAL_OT_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Material"; + ot->idname = "MATERIAL_OT_duplicate"; + ot->description = "Duplicate an existing material"; + + /* api callbacks */ + ot->exec = duplicate_material_exec; + ot->poll = object_materials_supported_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} /* -------------------------------------------------------------------- */ -/** \name New Texture Operator +/** \name Create Texture Operators * \{ */ -static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) +static void texture_creation_assign(bContext *C, Tex *tex) { - Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; - Main *bmain = CTX_data_main(C); PointerRNA ptr, idptr; PropertyRNA *prop; - /* add or copy texture */ - if (tex) { - tex = (Tex *)BKE_id_copy(bmain, &tex->id); - } - else { - tex = BKE_texture_add(bmain, DATA_("Texture")); - } - /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); @@ -839,6 +886,14 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } +} + +static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + Tex *tex = BKE_texture_add(bmain, DATA_("Texture")); + + texture_creation_assign(C, tex); WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, tex); @@ -859,31 +914,53 @@ void TEXTURE_OT_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } +static int duplicate_texture_exec(bContext *C, wmOperator *op) +{ + Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; + + if (!tex) { + BKE_report(op->reports, + RPT_ERROR, + "Incorrect context for duplicating a texture (did not find texture to duplicate)"); + return OPERATOR_CANCELLED; + } + + /* add or copy texture */ + Main *bmain = CTX_data_main(C); + tex = (Tex *)BKE_id_copy(bmain, &tex->id); + + texture_creation_assign(C, tex); + + WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, tex); + + return OPERATOR_FINISHED; +} + +void TEXTURE_OT_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Texture"; + ot->idname = "TEXTURE_OT_duplicate"; + ot->description = "Duplicate an existing texture"; + + /* api callbacks */ + ot->exec = duplicate_texture_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + /** \} */ /* -------------------------------------------------------------------- */ -/** \name new world operator +/** \name Create world operators * \{ */ -static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) +static void world_creation_assign(bContext *C, World *wo) { - World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data; - Main *bmain = CTX_data_main(C); PointerRNA ptr, idptr; PropertyRNA *prop; - /* add or copy world */ - if (wo) { - World *new_wo = (World *)BKE_id_copy_ex( - bmain, &wo->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); - wo = new_wo; - } - else { - wo = BKE_world_add(bmain, DATA_("World")); - ED_node_shader_default(C, &wo->id); - wo->use_nodes = true; - } - /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); @@ -896,6 +973,17 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } +} + +static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + + World *wo = BKE_world_add(bmain, DATA_("World")); + ED_node_shader_default(C, &wo->id); + wo->use_nodes = true; + + world_creation_assign(C, wo); WM_event_add_notifier(C, NC_WORLD | NA_ADDED, wo); @@ -907,7 +995,7 @@ void WORLD_OT_new(wmOperatorType *ot) /* identifiers */ ot->name = "New World"; ot->idname = "WORLD_OT_new"; - ot->description = "Create a new world Data-Block"; + ot->description = "Create a new world data-block"; /* api callbacks */ ot->exec = new_world_exec; @@ -916,6 +1004,36 @@ void WORLD_OT_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } +static int duplicate_world_exec(bContext *C, wmOperator *UNUSED(op)) +{ + World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data; + + if (wo) { + Main *bmain = CTX_data_main(C); + wo = (World *)BKE_id_copy(bmain, &wo->id); + } + + world_creation_assign(C, wo); + + WM_event_add_notifier(C, NC_WORLD | NA_ADDED, wo); + + return OPERATOR_FINISHED; +} + +void WORLD_OT_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate World"; + ot->idname = "WORLD_OT_duplicate"; + ot->description = "Duplicate an existing world data-block"; + + /* api callbacks */ + ot->exec = duplicate_world_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 244ebea5bbe..1dfe606be78 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -604,7 +604,7 @@ static eContextResult screen_ctx_sequences(const bContext *C, bContextDataResult { wmWindow *win = CTX_wm_window(C); Scene *scene = WM_window_get_active_scene(win); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) { CTX_data_list_add(result, &scene->id, &RNA_Sequence, seq); @@ -618,7 +618,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) { if (seq->flag & SELECT) { @@ -635,7 +635,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) { if (seq->flag & SELECT && !(seq->flag & SEQ_LOCK)) { @@ -649,8 +649,6 @@ static eContextResult screen_ctx_selected_editable_sequences(const bContext *C, } static eContextResult screen_ctx_selected_nla_strips(const bContext *C, bContextDataResult *result) { - wmWindow *win = CTX_wm_window(C); - Scene *scene = WM_window_get_active_scene(win); bAnimContext ac; if (ANIM_animdata_get_context(C, &ac) != 0) { ListBase anim_data = {NULL, NULL}; @@ -663,7 +661,7 @@ static eContextResult screen_ctx_selected_nla_strips(const bContext *C, bContext NlaTrack *nlt = (NlaTrack *)ale->data; LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) { if (strip->flag & NLASTRIP_FLAG_SELECT) { - CTX_data_list_add(result, &scene->id, &RNA_NlaStrip, strip); + CTX_data_list_add(result, ale->id, &RNA_NlaStrip, strip); } } } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 6be2fb8004b..be52874ed0b 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1133,12 +1133,11 @@ void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene) ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type) { - wmWindow *win = CTX_wm_window(C); ScrArea *newsa = NULL; SpaceLink *newsl; if (!area || area->full == NULL) { - newsa = ED_screen_state_toggle(C, win, area, SCREENMAXIMIZED); + newsa = ED_screen_state_maximized_create(C); } if (!newsa) { @@ -1149,11 +1148,11 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type) newsl = newsa->spacedata.first; /* Tag the active space before changing, so we can identify it when user wants to go back. */ - if ((newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) { + if (newsl && (newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) { newsl->link_flag |= SPACE_FLAG_TYPE_WAS_ACTIVE; } - ED_area_newspace(C, newsa, type, newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY); + ED_area_newspace(C, newsa, type, (newsl && newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY)); return newsa; } @@ -1217,13 +1216,108 @@ void ED_screen_full_restore(bContext *C, ScrArea *area) } /** - * this function toggles: if area is maximized/full then the parent will be restored + * \param toggle_area: If this is set, its space data will be swapped with the one of the new emtpy + * area, when toggling back it can be swapped back again. + * \return The newly created screen with the non-normal area. + */ +static bScreen *screen_state_to_nonnormal(bContext *C, + wmWindow *win, + ScrArea *toggle_area, + int state) +{ + Main *bmain = CTX_data_main(C); + WorkSpace *workspace = WM_window_get_active_workspace(win); + + /* change from SCREENNORMAL to new state */ + WorkSpaceLayout *layout_new; + ScrArea *newa; + char newname[MAX_ID_NAME - 2]; + + BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL)); + + bScreen *oldscreen = WM_window_get_active_screen(win); + + oldscreen->state = state; + BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal"); + + layout_new = ED_workspace_layout_add(bmain, workspace, win, newname); + + bScreen *screen = BKE_workspace_layout_screen_get(layout_new); + screen->state = state; + screen->redraws_flag = oldscreen->redraws_flag; + screen->temp = oldscreen->temp; + screen->flag = oldscreen->flag; + + /* timer */ + screen->animtimer = oldscreen->animtimer; + oldscreen->animtimer = NULL; + + newa = (ScrArea *)screen->areabase.first; + + /* swap area */ + if (toggle_area) { + ED_area_data_swap(newa, toggle_area); + newa->flag = toggle_area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */ + } + + if (state == SCREENFULL) { + /* temporarily hide global areas */ + LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) { + glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN; + } + /* temporarily hide the side panels/header */ + LISTBASE_FOREACH (ARegion *, region, &newa->regionbase) { + region->flagfullscreen = region->flag; + + if (ELEM(region->regiontype, + RGN_TYPE_UI, + RGN_TYPE_HEADER, + RGN_TYPE_TOOL_HEADER, + RGN_TYPE_FOOTER, + RGN_TYPE_TOOLS, + RGN_TYPE_NAV_BAR, + RGN_TYPE_EXECUTE)) { + region->flag |= RGN_FLAG_HIDDEN; + } + } + } + + if (toggle_area) { + toggle_area->full = oldscreen; + } + newa->full = oldscreen; + + ED_screen_change(C, screen); + ED_area_tag_refresh(newa); + + return screen; +} + +/** + * Create a new temporary screen with a maximized, empty area. + * This can be closed with #ED_screen_state_toggle(). + * + * Use this to just create a new maximized screen/area, rather than maximizing an existing one. + * Otherwise, maximize with #ED_screen_state_toggle(). + */ +ScrArea *ED_screen_state_maximized_create(bContext *C) +{ + bScreen *screen = screen_state_to_nonnormal(C, CTX_wm_window(C), NULL, SCREENMAXIMIZED); + return screen->areabase.first; +} + +/** + * This function toggles: if area is maximized/full then the parent will be restored. + * + * Use #ED_screen_state_maximized_create() if you do not want the toggle behavior when changing to + * a maximized area. I.e. if you just want to open a new maximized screen/area, not maximize a + * specific area. In the former case, space data of the maximized and non-maximized area should be + * independent, in the latter it should be the same. * * \warning \a area may be freed. */ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const short state) { - Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); WorkSpace *workspace = WM_window_get_active_workspace(win); @@ -1257,7 +1351,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const screen->state = SCREENNORMAL; screen->flag = oldscreen->flag; - /* find old area to restore from */ + /* Find old area we may have swapped dummy space data to. It's swapped back here. */ ScrArea *fullsa = NULL; LISTBASE_FOREACH (ScrArea *, old, &screen->areabase) { /* area to restore from is always first */ @@ -1271,13 +1365,6 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const area->full = NULL; - if (fullsa == NULL) { - if (G.debug & G_DEBUG) { - printf("%s: something wrong in areafullscreen\n", __func__); - } - return NULL; - } - if (state == SCREENFULL) { /* unhide global areas */ LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) { @@ -1289,14 +1376,16 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const } } - ED_area_data_swap(fullsa, area); + if (fullsa) { + ED_area_data_swap(fullsa, area); + ED_area_tag_refresh(fullsa); + } /* animtimer back */ screen->animtimer = oldscreen->animtimer; oldscreen->animtimer = NULL; ED_screen_change(C, screen); - ED_area_tag_refresh(fullsa); BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old); @@ -1307,68 +1396,16 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const screen->skip_handling = true; } else { - /* change from SCREENNORMAL to new state */ - WorkSpaceLayout *layout_new; - ScrArea *newa; - char newname[MAX_ID_NAME - 2]; - - BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL)); - - bScreen *oldscreen = WM_window_get_active_screen(win); - - oldscreen->state = state; - BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal"); - - layout_new = ED_workspace_layout_add(bmain, workspace, win, newname); - - screen = BKE_workspace_layout_screen_get(layout_new); - screen->state = state; - screen->redraws_flag = oldscreen->redraws_flag; - screen->temp = oldscreen->temp; - screen->flag = oldscreen->flag; - - /* timer */ - screen->animtimer = oldscreen->animtimer; - oldscreen->animtimer = NULL; + ScrArea *toggle_area = area; /* use random area when we have no active one, e.g. when the * mouse is outside of the window and we open a file browser */ - if (!area || area->global) { - area = oldscreen->areabase.first; + if (!toggle_area || toggle_area->global) { + bScreen *oldscreen = WM_window_get_active_screen(win); + toggle_area = oldscreen->areabase.first; } - newa = (ScrArea *)screen->areabase.first; - - /* copy area */ - ED_area_data_swap(newa, area); - newa->flag = area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */ - - if (state == SCREENFULL) { - /* temporarily hide global areas */ - LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) { - glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN; - } - /* temporarily hide the side panels/header */ - LISTBASE_FOREACH (ARegion *, region, &newa->regionbase) { - region->flagfullscreen = region->flag; - - if (ELEM(region->regiontype, - RGN_TYPE_UI, - RGN_TYPE_HEADER, - RGN_TYPE_TOOL_HEADER, - RGN_TYPE_FOOTER, - RGN_TYPE_TOOLS, - RGN_TYPE_NAV_BAR, - RGN_TYPE_EXECUTE)) { - region->flag |= RGN_FLAG_HIDDEN; - } - } - } - - area->full = oldscreen; - newa->full = oldscreen; - - ED_screen_change(C, screen); + screen = screen_state_to_nonnormal(C, win, toggle_area, state); } /* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */ @@ -1412,9 +1449,6 @@ ScrArea *ED_screen_temp_space_open(bContext *C, area->flag |= AREA_FLAG_STACKED_FULLSCREEN; ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY; } - else if (ctx_area != NULL && ctx_area->spacetype == space_type) { - area = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_area, SCREENMAXIMIZED); - } else { area = ED_screen_full_newspace(C, ctx_area, (int)space_type); ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY; diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 72b3b344813..8768404d74f 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3918,7 +3918,7 @@ static void SCREEN_OT_region_quadview(wmOperatorType *ot) { /* identifiers */ ot->name = "Toggle Quad View"; - ot->description = "Split selected area into camera, front, right & top views"; + ot->description = "Split selected area into camera, front, right, and top views"; ot->idname = "SCREEN_OT_region_quadview"; /* api callbacks */ @@ -5509,7 +5509,8 @@ void ED_operatortypes_screen(void) WM_operatortype_append(ED_OT_undo_redo); WM_operatortype_append(ED_OT_undo_history); - WM_operatortype_append(ED_OT_flush_edits); + WM_operatortype_append(ED_OT_lib_id_load_custom_preview); + WM_operatortype_append(ED_OT_lib_id_generate_preview); } /** \} */ diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 9bf3d2610d8..fff8d27ef5b 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -32,6 +32,7 @@ set(INC ../../windowmanager ../../../../intern/atomic ../../../../intern/clog + ../../../../intern/eigen ../../../../intern/glew-mx ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 3a6b91443a0..324fd5d3075 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -40,6 +40,7 @@ #include "IMB_imbuf_types.h" #include "DNA_brush_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -934,7 +935,7 @@ void PAINT_OT_grab_clone(wmOperatorType *ot) -FLT_MAX, FLT_MAX, "Delta", - "Delta offset of clone image in 0.0..1.0 coordinates", + "Delta offset of clone image in 0.0 to 1.0 coordinates", -1.0f, 1.0f); } diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 8c16300a047..cca4ffd4d78 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -6748,7 +6748,7 @@ void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot) "Generated Type", "Fill the image with a grid for UV map testing"); RNA_def_boolean( - ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); + ot->srna, "float", 0, "32-bit Float", "Create image with 32-bit floating-point bit depth"); } static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op)) @@ -6781,7 +6781,7 @@ static bool add_simple_uvs_poll(bContext *C) void PAINT_OT_add_simple_uvs(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add simple UVs"; + ot->name = "Add Simple UVs"; ot->description = "Add cube map uvs on mesh"; ot->idname = "PAINT_OT_add_simple_uvs"; diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 175d98ba9aa..3ca0d853d6a 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -43,7 +43,6 @@ struct wmEvent; struct wmKeyConfig; struct wmOperator; struct wmOperatorType; -struct wmWindowManager; enum ePaintMode; enum ePaintSymmetryFlags; diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 4bfb4f140bc..713049137ce 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -1554,6 +1554,11 @@ static int sculpt_trim_gesture_box_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + if (ss->totvert == 0) { + /* No geometry to trim or to detect a valid position for the trimming shape. */ + return OPERATOR_CANCELLED; + } + SculptGestureContext *sgcontext = sculpt_gesture_init_from_box(C, op); if (!sgcontext) { return OPERATOR_CANCELLED; @@ -1591,6 +1596,11 @@ static int sculpt_trim_gesture_lasso_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + if (ss->totvert == 0) { + /* No geometry to trim or to detect a valid position for the trimming shape. */ + return OPERATOR_CANCELLED; + } + SculptGestureContext *sgcontext = sculpt_gesture_init_from_lasso(C, op); if (!sgcontext) { return OPERATOR_CANCELLED; diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c index b831687ca67..96d22fe4a21 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c @@ -401,7 +401,7 @@ void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Vertex Paint Bright/Contrast"; + ot->name = "Vertex Paint Brightness/Contrast"; ot->idname = "PAINT_OT_vertex_color_brightness_contrast"; ot->description = "Adjust vertex color brightness/contrast"; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index dd654b41ffa..bf55d6a323e 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1539,6 +1539,7 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool) SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER, SCULPT_TOOL_POSE, + SCULPT_TOOL_DISPLACEMENT_SMEAR, SCULPT_TOOL_BOUNDARY, SCULPT_TOOL_CLOTH, SCULPT_TOOL_PAINT, @@ -2703,6 +2704,7 @@ static float brush_strength(const Sculpt *sd, final_pressure = pressure * pressure; return final_pressure * overlap * feather; case SCULPT_TOOL_SMEAR: + case SCULPT_TOOL_DISPLACEMENT_SMEAR: return alpha * pressure * overlap * feather; case SCULPT_TOOL_CLAY_STRIPS: /* Clay Strips needs less strength to compensate the curve. */ @@ -3446,6 +3448,151 @@ static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **node /** \} */ +/** \name Sculpt Multires Displacement Smear Brush + * \{ */ + +static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.vertex, + thread_id); + + float current_disp[3]; + float current_disp_norm[3]; + float interp_limit_surface_disp[3]; + + copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]); + + switch (brush->smear_deform_type) { + case BRUSH_SMEAR_DEFORM_DRAG: + sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); + break; + case BRUSH_SMEAR_DEFORM_PINCH: + sub_v3_v3v3(current_disp, ss->cache->location, vd.co); + break; + case BRUSH_SMEAR_DEFORM_EXPAND: + sub_v3_v3v3(current_disp, vd.co, ss->cache->location); + break; + } + + normalize_v3_v3(current_disp_norm, current_disp); + mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); + + float weights_accum = 1.0f; + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { + float vertex_disp[3]; + float vertex_disp_norm[3]; + float neighbor_limit_co[3]; + SCULPT_vertex_limit_surface_get(ss, ni.vertex, neighbor_limit_co); + sub_v3_v3v3(vertex_disp, + ss->cache->limit_surface_co[ni.index], + ss->cache->limit_surface_co[vd.index]); + const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index]; + normalize_v3_v3(vertex_disp_norm, vertex_disp); + if (dot_v3v3(current_disp_norm, vertex_disp_norm) < 0.0f) { + const float disp_interp = clamp_f( + -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f); + madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp); + weights_accum += disp_interp; + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum); + + float new_co[3]; + add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp); + interp_v3_v3v3(vd.co, vd.co, new_co, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_displacement_smear_store_prev_disp_task_cb_ex( + void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + sub_v3_v3v3(ss->cache->prev_displacement[vd.index], + SCULPT_vertex_co_get(ss, vd.vertex), + ss->cache->limit_surface_co[vd.index]); + } + BKE_pbvh_vertex_iter_end; +} + +static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + SculptSession *ss = ob->sculpt; + + BKE_curvemapping_init(brush->curve); + SCULPT_vertex_random_access_ensure(ss); + + const int totvert = SCULPT_vertex_count_get(ss); + if (!ss->cache->prev_displacement) { + ss->cache->prev_displacement = MEM_malloc_arrayN( + totvert, sizeof(float[3]), "prev displacement"); + ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co"); + + for (int i = 0; i < totvert; i++) { + SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_limit_surface_get(ss, vref, ss->cache->limit_surface_co[i]); + sub_v3_v3v3(ss->cache->prev_displacement[i], + SCULPT_vertex_co_get(ss, vref), + ss->cache->limit_surface_co[i]); + } + } + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range( + 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings); +} + +/** \} */ + static void do_draw_brush_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) @@ -4578,6 +4725,8 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, (len_v3(grab_delta) / ss->cache->radius)) : 0.0f; + const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; SculptBrushTest test; @@ -4585,18 +4734,28 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + KelvinletParams params; + BKE_kelvinlet_init_params(¶ms, ss->cache->radius, bstrength, 1.0f, 0.4f); + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sq_fn(&test, vd.co)) { - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.vertex, - thread_id); + if (do_elastic || sculpt_brush_test_sq_fn(&test, vd.co)) { + + float fade; + if (do_elastic) { + fade = 1.0f; + } + else { + fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.vertex, + thread_id); + } mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -4635,6 +4794,17 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, add_v3_v3(proxy[vd.i], delta_rotate); } + if (do_elastic) { + float disp[3]; + BKE_kelvinlet_grab_triscale(disp, ¶ms, vd.co, ss->cache->location, proxy[vd.i]); + mul_v3_fl(disp, bstrength * 20.0f); + if (vd.mask) { + mul_v3_fl(disp, 1.0f - *vd.mask); + } + mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex)); + copy_v3_v3(proxy[vd.i], disp); + } + if (vd.mvert) { vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } @@ -6021,7 +6191,8 @@ static void sculpt_topology_update(Sculpt *sd, ss->cache->radius, (brush->flag & BRUSH_FRONTFACE) != 0, (brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE), - symidx, brush->sculpt_tool != SCULPT_TOOL_DRAW_SHARP); + symidx, + brush->sculpt_tool != SCULPT_TOOL_DRAW_SHARP); } MEM_SAFE_FREE(nodes); @@ -6086,45 +6257,12 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe /* Build a list of all nodes that are potentially within the brush's area of influence */ - /* These brushes need to update all nodes as they are not constrained by the brush radius */ - /* Elastic deform needs all nodes to avoid artifacts as the effect of the brush is not - * constrained by the radius. */ - /* Pose needs all nodes because it applies all symmetry iterations at the same time and the IK - * chain can grow to any area of the model. */ - /* This can be optimized by filtering the nodes after calculating the chain. */ - if (ELEM(brush->sculpt_tool, - SCULPT_TOOL_ELASTIC_DEFORM, - SCULPT_TOOL_POSE, - SCULPT_TOOL_BOUNDARY)) { + if (SCULPT_tool_needs_all_pbvh_nodes(brush)) { + /* These brushes need to update all nodes as they are not constrained by the brush radius */ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); } else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) { - if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_LOCAL) { - SculptSearchSphereData data = { - .ss = ss, - .sd = sd, - .radius_squared = square_f(ss->cache->initial_radius * (1.0 + brush->cloth_sim_limit)), - .original = false, - .ignore_fully_ineffective = false, - .center = ss->cache->initial_location, - }; - BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); - } - if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC) { - SculptSearchSphereData data = { - .ss = ss, - .sd = sd, - .radius_squared = square_f(ss->cache->radius * (1.0 + brush->cloth_sim_limit)), - .original = false, - .ignore_fully_ineffective = false, - .center = ss->cache->location, - }; - BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); - } - else { - /* Gobal simulation, get all nodes. */ - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - } + nodes = SCULPT_cloth_brush_affected_nodes_gather(ss, brush, &totnode); } else { const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : @@ -6160,6 +6298,17 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe } } + /* Initialize automasking cache. For anchored brushes with spherical falloff, we start off with + * zero radius, thus we have no pbvh nodes on the first brush step. */ + if (totnode || + ((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) { + if (SCULPT_stroke_is_first_brush_step(ss->cache)) { + if (SCULPT_is_automasking_enabled(sd, ss, brush)) { + ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob); + } + } + } + /* Only act if some verts are inside the brush area. */ if (totnode) { float location[3]; @@ -6223,12 +6372,6 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe update_brush_local_mat(sd, ob); } - if (SCULPT_stroke_is_first_brush_step(ss->cache)) { - if (SCULPT_is_automasking_enabled(sd, ss, brush)) { - ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob); - } - } - if (brush->sculpt_tool == SCULPT_TOOL_POSE && SCULPT_stroke_is_first_brush_step(ss->cache)) { SCULPT_pose_brush_init(sd, ob, ss, brush); } @@ -6347,6 +6490,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe case SCULPT_TOOL_DISPLACEMENT_ERASER: do_displacement_eraser_brush(sd, ob, nodes, totnode); break; + case SCULPT_TOOL_DISPLACEMENT_SMEAR: + do_displacement_smear_brush(sd, ob, nodes, totnode); + break; case SCULPT_TOOL_PAINT: SCULPT_do_paint_brush(sd, ob, nodes, totnode); break; @@ -6936,6 +7082,8 @@ static const char *sculpt_tool_name(Sculpt *sd) return "Draw Face Sets"; case SCULPT_TOOL_DISPLACEMENT_ERASER: return "Multires Displacement Eraser"; + case SCULPT_TOOL_DISPLACEMENT_SMEAR: + return "Multires Displacement Smear"; case SCULPT_TOOL_PAINT: return "Paint Brush"; case SCULPT_TOOL_SMEAR: @@ -6958,6 +7106,8 @@ void SCULPT_cache_free(StrokeCache *cache) MEM_SAFE_FREE(cache->layer_displacement_factor); MEM_SAFE_FREE(cache->prev_colors); MEM_SAFE_FREE(cache->detail_directions); + MEM_SAFE_FREE(cache->prev_displacement); + MEM_SAFE_FREE(cache->limit_surface_co); if (cache->pose_ik_chain) { SCULPT_pose_ik_chain_free(cache->pose_ik_chain); @@ -7129,6 +7279,7 @@ static void sculpt_update_cache_invariants( SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY, + SCULPT_TOOL_DISPLACEMENT_SMEAR, SCULPT_TOOL_DISPLACEMENT_ERASER) && (sd->gravity_factor > 0.0f)); /* Get gravity vector in world space. */ @@ -9160,7 +9311,7 @@ static int sculpt_sample_color_invoke(bContext *C, static void SCULPT_OT_sample_color(wmOperatorType *ot) { /* identifiers */ - ot->name = "Sample color"; + ot->name = "Sample Color"; ot->idname = "SCULPT_OT_sample_color"; ot->description = "Sample the vertex color of the active vertex"; diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index cd8f609b598..1eab35ae0e5 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -119,6 +119,43 @@ static void cloth_brush_simulation_location_get(SculptSession *ss, copy_v3_v3(r_location, ss->cache->location); } +PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss, + Brush *brush, + int *r_totnode) +{ + BLI_assert(ss->cache); + BLI_assert(brush->sculpt_tool == SCULPT_TOOL_CLOTH); + PBVHNode **nodes = NULL; + + switch (brush->cloth_simulation_area_type) { + case BRUSH_CLOTH_SIMULATION_AREA_LOCAL: { + SculptSearchSphereData data = { + .ss = ss, + .radius_squared = square_f(ss->cache->initial_radius * (1.0 + brush->cloth_sim_limit)), + .original = false, + .ignore_fully_ineffective = false, + .center = ss->cache->initial_location, + }; + BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode); + } break; + case BRUSH_CLOTH_SIMULATION_AREA_GLOBAL: + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, r_totnode); + break; + case BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC: { + SculptSearchSphereData data = { + .ss = ss, + .radius_squared = square_f(ss->cache->radius * (1.0 + brush->cloth_sim_limit)), + .original = false, + .ignore_fully_ineffective = false, + .center = ss->cache->location, + }; + BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode); + } break; + } + + return nodes; +} + static float cloth_brush_simulation_falloff_get(const Brush *brush, const float radius, const float location[3], diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index c044fec0d7b..0ee8114aba2 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -363,7 +363,7 @@ void SCULPT_OT_sample_detail_size(wmOperatorType *ot) 0, SHRT_MAX, "Location", - "Screen Coordinates of sampling", + "Screen coordinates of sampling", 0, SHRT_MAX); RNA_def_enum(ot->srna, diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index 4227c14df76..0a02f8b543b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -42,6 +42,7 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_mesh.h" +#include "BKE_mesh_fair.h" #include "BKE_mesh_mapping.h" #include "BKE_multires.h" #include "BKE_node.h" @@ -1067,6 +1068,8 @@ typedef enum eSculptFaceSetEditMode { SCULPT_FACE_SET_EDIT_GROW = 0, SCULPT_FACE_SET_EDIT_SHRINK = 1, SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY = 2, + SCULPT_FACE_SET_EDIT_FAIR_POSITIONS = 3, + SCULPT_FACE_SET_EDIT_FAIR_TANGENCY = 4, } eSculptFaceSetEditMode; static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = { @@ -1091,6 +1094,22 @@ static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = { "Delete Geometry", "Deletes the faces that are assigned to the Face Set", }, + { + SCULPT_FACE_SET_EDIT_FAIR_POSITIONS, + "FAIR_POSITIONS", + 0, + "Fair Positions", + "Creates a smooth as possible geometry patch from the Face Set minimizing changes in " + "vertex positions", + }, + { + SCULPT_FACE_SET_EDIT_FAIR_TANGENCY, + "FAIR_TANGENCY", + 0, + "Fair Tangency", + "Creates a smooth as possible geometry patch from the Face Set minimizing changes in " + "vertex tangents", + }, {0, NULL, 0, NULL, NULL}, }; @@ -1177,7 +1196,7 @@ static void sculpt_face_set_shrink(Object *ob, const bool modify_hidden) { if (ss && ss->bm) { - //XXX implement me + // XXX implement me return; } @@ -1279,6 +1298,33 @@ static void sculpt_face_set_delete_geometry(Object *ob, BM_mesh_free(bm); } +static void sculpt_face_set_edit_fair_face_set(Object *ob, + const int active_face_set_id, + const int fair_order) +{ + SculptSession *ss = ob->sculpt; + + const int totvert = SCULPT_vertex_count_get(ss); + + Mesh *mesh = ob->data; + bool *fair_vertices = MEM_malloc_arrayN(sizeof(bool), totvert, "fair vertices"); + + SCULPT_vertex_random_access_ensure(ss); + SCULPT_boundary_info_ensure(ob); + + for (int i = 0; i < totvert; i++) { + SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i); + + fair_vertices[i] = !SCULPT_vertex_is_boundary(ss, vref) && + SCULPT_vertex_has_face_set(ss, vref, active_face_set_id) && + SCULPT_vertex_has_unique_face_set(ss, vref); + } + + MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss); + BKE_mesh_prefair_and_fair_vertices(mesh, mvert, fair_vertices, fair_order); + MEM_freeN(fair_vertices); +} + static void sculpt_face_set_apply_edit(Object *ob, const int active_face_set_id, const int mode, @@ -1302,6 +1348,12 @@ static void sculpt_face_set_apply_edit(Object *ob, case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY: sculpt_face_set_delete_geometry(ob, ss, active_face_set_id, modify_hidden); break; + case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS: + sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_POSITION); + break; + case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY: + sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_TANGENCY); + break; } } @@ -1328,6 +1380,16 @@ static bool sculpt_face_set_edit_is_operation_valid(SculptSession *ss, return false; } } + + if (ELEM(mode, SCULPT_FACE_SET_EDIT_FAIR_POSITIONS, SCULPT_FACE_SET_EDIT_FAIR_TANGENCY)) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { + /* TODO: Multires topology representation using grids and duplicates can't be used directly + * by the fair algorithm. Multires topology needs to be exposed in a different way or + * converted to a mesh for this operation. */ + return false; + } + } + return true; } @@ -1385,11 +1447,38 @@ static void sculpt_face_set_edit_modify_face_sets(Object *ob, MEM_freeN(nodes); } +static void sculpt_face_set_edit_modify_coordinates(bContext *C, + Object *ob, + const int active_face_set, + const eSculptFaceSetEditMode mode) +{ + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = ob->sculpt; + PBVH *pbvh = ss->pbvh; + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); + SCULPT_undo_push_begin(ob, "face set edit"); + for (int i = 0; i < totnode; i++) { + BKE_pbvh_node_mark_update(nodes[i]); + SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COORDS); + } + sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, false); + + if (ss->deform_modifiers_active || ss->shapekey_active) { + SCULPT_flush_stroke_deform(sd, ob, true); + } + SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS); + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); + SCULPT_undo_push_end(); + MEM_freeN(nodes); +} + static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); const int mode = RNA_enum_get(op->ptr, "mode"); const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden"); @@ -1418,6 +1507,10 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven case SCULPT_FACE_SET_EDIT_SHRINK: sculpt_face_set_edit_modify_face_sets(ob, active_face_set, mode, modify_hidden); break; + case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS: + case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY: + sculpt_face_set_edit_modify_coordinates(C, ob, active_face_set, mode); + break; } SCULPT_tag_update_overlays(C); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c index ab910e3e0eb..38d2904e98a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c @@ -328,9 +328,9 @@ void SCULPT_OT_color_filter(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* rna */ - RNA_def_enum(ot->srna, "type", prop_color_filter_types, COLOR_FILTER_HUE, "Filter type", ""); + RNA_def_enum(ot->srna, "type", prop_color_filter_types, COLOR_FILTER_HUE, "Filter Type", ""); RNA_def_float( - ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f); + ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f); PropertyRNA *prop = RNA_def_float_color( ot->srna, "fill_color", 3, NULL, 0.0f, FLT_MAX, "Fill Color", "", 0.0f, 1.0f); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index 92142625e7b..5ce5a862cbe 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -80,12 +80,12 @@ static EnumPropertyItem prop_mask_filter_types[] = { {MASK_FILTER_CONTRAST_INCREASE, "CONTRAST_INCREASE", 0, - "Increase contrast", + "Increase Contrast", "Increase the contrast of the paint mask"}, {MASK_FILTER_CONTRAST_DECREASE, "CONTRAST_DECREASE", 0, - "Decrease contrast", + "Decrease Contrast", "Decrease the contrast of the paint mask"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 0001c15a31d..b8b6ebae25f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -778,15 +778,15 @@ void SCULPT_OT_mesh_filter(struct wmOperatorType *ot) "type", prop_mesh_filter_types, MESH_FILTER_INFLATE, - "Filter type", + "Filter Type", "Operation that is going to be applied to the mesh"); RNA_def_float( - ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f); + ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f); RNA_def_enum_flag(ot->srna, "deform_axis", prop_mesh_filter_deform_axis_items, MESH_FILTER_DEFORM_X | MESH_FILTER_DEFORM_Y | MESH_FILTER_DEFORM_Z, - "Deform axis", + "Deform Axis", "Apply the deformation in the selected axis"); RNA_def_enum(ot->srna, "orientation", diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 57a0a47df97..7aef6f71154 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -39,7 +39,6 @@ struct AutomaskingCache; struct KeyBlock; struct Object; -struct SculptPoseIKChainSegment; struct SculptUndoNode; struct bContext; @@ -436,6 +435,10 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr, const float outline_col[3], float outline_alpha); +PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss, + Brush *brush, + int *r_totnode); + BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) { return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type, @@ -447,6 +450,38 @@ BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM); } +BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush) +{ + if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) { + /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect + * of the Kelvinlet is not constrained by the radius. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_POSE) { + /* Pose needs all nodes because it applies all symmetry iterations at the same time + * and the IK chain can grow to any area of the model. */ + /* TODO: This can be optimized by filtering the nodes after calculating the chain. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) { + /* Boundary needs all nodes because it is not possible to know where the boundary + * deformation is going to be propagated before calculating it. */ + /* TODO: after calculating the boundary info in the first iteration, it should be + * possible to get the nodes that have vertices included in any boundary deformation + * and cache them. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK && + brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC) { + /* Snake hook in elastic deform type has same requirements as the elastic deform tool. */ + return true; + } + return false; +} + /* Pose Brush. */ void SCULPT_do_pose_brush(struct Sculpt *sd, struct Object *ob, @@ -912,6 +947,10 @@ typedef struct StrokeCache { float (*prev_colors)[4]; + /* Multires Displacement Smear. */ + float (*prev_displacement)[3]; + float (*limit_surface_co)[3]; + /* The rest is temporary storage that isn't saved as a property */ bool first_time; /* Beginning of stroke may do some things special */ diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index c6961cc9d4b..34617804888 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -52,7 +52,7 @@ #include "RNA_define.h" #include "RNA_enum_types.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" #include "UI_interface.h" @@ -259,7 +259,7 @@ static void sound_update_animation_flags(Scene *scene) scene->id.tag |= LIB_TAG_DOIT; SEQ_ALL_BEGIN (scene->ed, seq) { - BKE_sequencer_recursive_apply(seq, sound_update_animation_flags_fn, scene); + SEQ_iterator_recursive_apply(seq, sound_update_animation_flags_fn, scene); } SEQ_ALL_END; @@ -518,27 +518,27 @@ static bool sound_mixdown_draw_check_prop(PointerRNA *UNUSED(ptr), static void sound_mixdown_draw(bContext *C, wmOperator *op) { static const EnumPropertyItem pcm_format_items[] = { - {AUD_FORMAT_U8, "U8", 0, "U8", "8 bit unsigned"}, - {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"}, + {AUD_FORMAT_U8, "U8", 0, "U8", "8-bit unsigned"}, + {AUD_FORMAT_S16, "S16", 0, "S16", "16-bit signed"}, # ifdef WITH_SNDFILE - {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"}, + {AUD_FORMAT_S24, "S24", 0, "S24", "24-bit signed"}, # endif - {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"}, - {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32 bit floating point"}, - {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64 bit floating point"}, + {AUD_FORMAT_S32, "S32", 0, "S32", "32-bit signed"}, + {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32-bit floating-point"}, + {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64-bit floating-point"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem mp3_format_items[] = { - {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"}, - {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"}, + {AUD_FORMAT_S16, "S16", 0, "S16", "16-bit signed"}, + {AUD_FORMAT_S32, "S32", 0, "S32", "32-bit signed"}, {0, NULL, 0, NULL, NULL}, }; # ifdef WITH_SNDFILE static const EnumPropertyItem flac_format_items[] = { - {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"}, - {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"}, + {AUD_FORMAT_S16, "S16", 0, "S16", "16-bit signed"}, + {AUD_FORMAT_S24, "S24", 0, "S24", "24-bit signed"}, {0, NULL, 0, NULL, NULL}, }; # endif @@ -672,12 +672,12 @@ static void SOUND_OT_mixdown(wmOperatorType *ot) { #ifdef WITH_AUDASPACE static const EnumPropertyItem format_items[] = { - {AUD_FORMAT_U8, "U8", 0, "U8", "8 bit unsigned"}, - {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"}, - {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"}, - {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"}, - {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32 bit floating point"}, - {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64 bit floating point"}, + {AUD_FORMAT_U8, "U8", 0, "U8", "8-bit unsigned"}, + {AUD_FORMAT_S16, "S16", 0, "S16", "16-bit signed"}, + {AUD_FORMAT_S24, "S24", 0, "S24", "24-bit signed"}, + {AUD_FORMAT_S32, "S32", 0, "S32", "32-bit signed"}, + {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32-bit floating-point"}, + {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64-bit floating-point"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index e20be9c8328..4d5a93f75e0 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -158,7 +158,78 @@ static void actedit_change_action(bContext *C, bAction *act) RNA_property_update(C, &ptr, prop); } -/* ******************** New Action Operator *********************** */ +/* ******************** New Action Operators *********************** */ + +static void action_creation_assign(bContext *C, + bAction *action, + PointerRNA *ptr, + PropertyRNA *prop) +{ + PointerRNA idptr; + /* Set the new action. + * NOTE: we can't use actedit_change_action, as this function is also called from the NLA. */ + RNA_id_pointer_create(&action->id, &idptr); + RNA_property_pointer_set(ptr, prop, idptr, NULL); + RNA_property_update(C, ptr, prop); +} + +/** + * Stash the previously active action to prevent it from being lost. + * \return The old action if any. + */ +static bAction *action_creation_stash_old(bContext *C, PointerRNA *ptr, PropertyRNA *prop) +{ + bAction *oldact = NULL; + AnimData *adt = NULL; + + if (prop) { + /* The operator was called from a button. */ + PointerRNA oldptr; + + oldptr = RNA_property_pointer_get(ptr, prop); + oldact = (bAction *)oldptr.owner_id; + + /* stash the old action to prevent it from being lost */ + if (ptr->type == &RNA_AnimData) { + adt = ptr->data; + } + else if (ptr->type == &RNA_SpaceDopeSheetEditor) { + adt = ED_actedit_animdata_from_context(C); + } + } + else { + adt = ED_actedit_animdata_from_context(C); + oldact = adt->action; + } + + if (!adt || !oldact) { + /* Found nothing to stash in current context. */ + return NULL; + } + + /* Perform stashing operation. */ + if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ptr->owner_id))) { + /* The stash operation will remove the user already + * (and unlink the action from the AnimData action slot). + * Hence, we must unset the ref to the action in the + * action editor too (if this is where we're being called from) + * first before setting the new action once it is created, + * or else the user gets decremented twice! + */ + if (ptr->type == &RNA_SpaceDopeSheetEditor) { + SpaceAction *saction = ptr->data; + saction->action = NULL; + } + } + else { +#if 0 + printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", + oldact->id.name); +#endif + } + + return oldact; +} /* Criteria: * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions... @@ -207,71 +278,17 @@ static bool action_new_poll(bContext *C) static int action_new_exec(bContext *C, wmOperator *UNUSED(op)) { - PointerRNA ptr, idptr; + PointerRNA ptr; PropertyRNA *prop; - bAction *oldact = NULL; - AnimData *adt = NULL; /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); - if (prop) { - /* The operator was called from a button. */ - PointerRNA oldptr; - - oldptr = RNA_property_pointer_get(&ptr, prop); - oldact = (bAction *)oldptr.owner_id; - - /* stash the old action to prevent it from being lost */ - if (ptr.type == &RNA_AnimData) { - adt = ptr.data; - } - else if (ptr.type == &RNA_SpaceDopeSheetEditor) { - adt = ED_actedit_animdata_from_context(C); - } - } - else { - adt = ED_actedit_animdata_from_context(C); - oldact = adt->action; - } - { - bAction *action = NULL; - - /* Perform stashing operation - But only if there is an action */ - if (adt && oldact) { - /* stash the action */ - if (BKE_nla_action_stash(adt)) { - /* The stash operation will remove the user already - * (and unlink the action from the AnimData action slot). - * Hence, we must unset the ref to the action in the - * action editor too (if this is where we're being called from) - * first before setting the new action once it is created, - * or else the user gets decremented twice! - */ - if (ptr.type == &RNA_SpaceDopeSheetEditor) { - SpaceAction *saction = ptr.data; - saction->action = NULL; - } - } - else { -#if 0 - printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", - oldact->id.name); -#endif - } - } - - /* create action */ - action = action_create_new(C, oldact); + action_creation_stash_old(C, &ptr, prop); - if (prop) { - /* set this new action - * NOTE: we can't use actedit_change_action, as this function is also called from the NLA - */ - RNA_id_pointer_create(&action->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr, NULL); - RNA_property_update(C, &ptr, prop); - } + bAction *action = action_create_new(C, NULL); + if (prop) { + action_creation_assign(C, action, &ptr, prop); } /* set notifier that keyframes have changed */ @@ -285,7 +302,7 @@ void ACTION_OT_new(wmOperatorType *ot) /* identifiers */ ot->name = "New Action"; ot->idname = "ACTION_OT_new"; - ot->description = "Create new action"; + ot->description = "Create a new action"; /* api callbacks */ ot->exec = action_new_exec; @@ -295,6 +312,45 @@ void ACTION_OT_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static int action_duplicate_assign_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PointerRNA ptr; + PropertyRNA *prop; + + /* hook into UI */ + UI_context_active_but_prop_get_templateID(C, &ptr, &prop); + + bAction *old_action = action_creation_stash_old(C, &ptr, prop); + + bAction *new_action = action_create_new(C, old_action); + if (prop) { + action_creation_assign(C, new_action, &ptr, prop); + } + + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); + + return OPERATOR_FINISHED; +} + +/** + * Duplicate an action assigned to a templateID and update it's assignment - based on UI context. + */ +void ACTION_OT_duplicate_assign(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate & Assign Action"; + ot->idname = "ACTION_OT_duplicate_assign"; + ot->description = "Create a copy of an existing action and assign it"; + + /* api callbacks */ + ot->exec = action_duplicate_assign_exec; + ot->poll = action_new_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + /* ******************* Action Push-Down Operator ******************** */ /* Criteria: @@ -339,7 +395,8 @@ static int action_pushdown_exec(bContext *C, wmOperator *op) } /* action can be safely added */ - BKE_nla_action_pushdown(adt); + const Object *ob = CTX_data_active_object(C); + BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(ob)); /* Stop displaying this action in this editor * NOTE: The editor itself doesn't set a user... @@ -384,7 +441,8 @@ static int action_stash_exec(bContext *C, wmOperator *op) } /* stash the action */ - if (BKE_nla_action_stash(adt)) { + Object *ob = CTX_data_active_object(C); + if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ob))) { /* The stash operation will remove the user already, * so the flushing step later shouldn't double up * the user-count fixes. Hence, we must unset this ref @@ -486,7 +544,8 @@ static int action_stash_create_exec(bContext *C, wmOperator *op) } /* stash the action */ - if (BKE_nla_action_stash(adt)) { + Object *ob = CTX_data_active_object(C); + if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ob))) { bAction *new_action = NULL; /* Create new action not based on the old one diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 167215b3813..d186cafb857 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -1827,7 +1827,7 @@ static const EnumPropertyItem prop_actkeys_mirror_types[] = { {ACTKEYS_MIRROR_XAXIS, "XAXIS", 0, - "By Values Over Value=0", + "By Values Over Zero Value", "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"}, {ACTKEYS_MIRROR_MARKER, "MARKER", diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index ffe0606c98f..4bce6c62a1a 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -106,6 +106,7 @@ void ACTION_OT_snap(struct wmOperatorType *ot); void ACTION_OT_mirror(struct wmOperatorType *ot); void ACTION_OT_new(struct wmOperatorType *ot); +void ACTION_OT_duplicate_assign(struct wmOperatorType *ot); void ACTION_OT_unlink(struct wmOperatorType *ot); void ACTION_OT_push_down(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index 7422c05511c..329c3a9f6f6 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -73,7 +73,9 @@ void action_operatortypes(void) WM_operatortype_append(ACTION_OT_copy); WM_operatortype_append(ACTION_OT_paste); + /* UI-context based operators. */ WM_operatortype_append(ACTION_OT_new); + WM_operatortype_append(ACTION_OT_duplicate_assign); WM_operatortype_append(ACTION_OT_unlink); WM_operatortype_append(ACTION_OT_push_down); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index ab5f1e0ab22..98e39520e99 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -1325,8 +1325,8 @@ void ACTION_OT_select_less(wmOperatorType *ot) /* defines for left-right select tool */ static const EnumPropertyItem prop_actkeys_leftright_select_types[] = { {ACTKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""}, - {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""}, - {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""}, + {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before Current Frame", ""}, + {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After Current Frame", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 10ce7b81954..10fa2c19919 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -40,6 +40,7 @@ #include "ED_anim_api.h" #include "ED_armature.h" +#include "ED_asset.h" #include "ED_clip.h" #include "ED_curve.h" #include "ED_fileselect.h" @@ -64,6 +65,7 @@ #include "ED_space_api.h" #include "ED_transform.h" #include "ED_userpref.h" +#include "ED_util.h" #include "ED_uvedit.h" #include "io_ops.h" @@ -105,6 +107,7 @@ void ED_spacetypes_init(void) ED_operatortypes_screen(); ED_operatortypes_anim(); ED_operatortypes_animchannels(); + ED_operatortypes_asset(); ED_operatortypes_gpencil(); ED_operatortypes_object(); ED_operatortypes_lattice(); @@ -122,6 +125,7 @@ void ED_spacetypes_init(void) ED_operatortypes_render(); ED_operatortypes_mask(); ED_operatortypes_io(); + ED_operatortypes_edutils(); ED_operatortypes_view2d(); ED_operatortypes_ui(); diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt index fa3e6a51036..c71e5e49d8d 100644 --- a/source/blender/editors/space_buttons/CMakeLists.txt +++ b/source/blender/editors/space_buttons/CMakeLists.txt @@ -51,6 +51,7 @@ endif() if(WITH_EXPERIMENTAL_FEATURES) add_definitions(-DWITH_GEOMETRY_NODES) + add_definitions(-DWITH_POINT_CLOUD) add_definitions(-DWITH_HAIR_NODES) endif() diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 8b39995a5c9..c1f29231f96 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -246,9 +246,11 @@ static bool buttons_context_path_data(ButsContextPath *path, int type) return true; } #endif +#ifdef WITH_POINT_CLOUD if (RNA_struct_is_a(ptr->type, &RNA_PointCloud) && (type == -1 || type == OB_POINTCLOUD)) { return true; } +#endif if (RNA_struct_is_a(ptr->type, &RNA_Volume) && (type == -1 || type == OB_VOLUME)) { return true; } @@ -812,7 +814,9 @@ const char *buttons_context_dir[] = { #ifdef WITH_HAIR_NODES "hair", #endif +#ifdef WITH_POINT_CLOUD "pointcloud", +#endif "volume", NULL, }; @@ -822,6 +826,11 @@ int /*eContextResult*/ buttons_context(const bContext *C, bContextDataResult *result) { SpaceProperties *sbuts = CTX_wm_space_properties(C); + if (sbuts && sbuts->path == NULL) { + /* path is cleared for SCREEN_OT_redo_last, when global undo does a file-read which clears the + * path (see lib_link_workspace_layout_restore). */ + buttons_context_compute(C, sbuts); + } ButsContextPath *path = sbuts ? sbuts->path : NULL; if (!path) { @@ -899,10 +908,12 @@ int /*eContextResult*/ buttons_context(const bContext *C, return CTX_RESULT_OK; } #endif +#ifdef WITH_POINT_CLOUD if (CTX_data_equals(member, "pointcloud")) { set_pointer_type(path, result, &RNA_PointCloud); return CTX_RESULT_OK; } +#endif if (CTX_data_equals(member, "volume")) { set_pointer_type(path, result, &RNA_Volume); return CTX_RESULT_OK; diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h index 0a0846cf216..74e7bc11c26 100644 --- a/source/blender/editors/space_buttons/buttons_intern.h +++ b/source/blender/editors/space_buttons/buttons_intern.h @@ -35,7 +35,6 @@ struct bContext; struct bContextDataResult; struct bNode; struct bNodeTree; -struct uiLayout; struct wmOperatorType; struct SpaceProperties_Runtime { diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index 8bdc2ed993f..8f57abf83ae 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -338,7 +338,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event) is_relative = BLI_path_is_rel(str); } - if (UNLIKELY(ptr.data == &U)) { + if (UNLIKELY(ptr.data == &U || is_userdef)) { is_relative = false; } diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index a95d0e3ea88..e0f603eb3d1 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -140,6 +140,7 @@ void uiTemplateMovieClip( ptr, propname, NULL, + NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 3f00e3114a5..8f36ccb019a 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -859,7 +859,7 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot) -FLT_MAX, FLT_MAX, "Location", - "Cursor location in normalized (0.0-1.0) coordinates", + "Cursor location in normalized (0.0 to 1.0) coordinates", -10.0f, 10.0f); RNA_def_property_flag(prop, PROP_HIDDEN); diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index a54faa41122..9b8e9e0e871 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -164,12 +164,12 @@ static bool id_drop_poll(bContext *UNUSED(C), const wmEvent *UNUSED(event), const char **UNUSED(tooltip)) { - return WM_drag_ID(drag, 0) != NULL; + return WM_drag_get_local_ID(drag, 0) != NULL; } static void id_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID(drag, 0); /* copy drag path to properties */ char *text = RNA_path_full_ID_py(G_MAIN, id); diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 4b277435f63..f2f7f9d82f9 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -25,6 +25,7 @@ #include <math.h> #include <string.h> +#include "BLI_alloca.h" #include "BLI_blenlib.h" #include "BLI_fileops_types.h" #include "BLI_math.h" @@ -134,6 +135,7 @@ static void draw_tile(int sx, int sy, int width, int height, int colorid, int sh } static void file_draw_icon(uiBlock *block, + const FileDirEntry *file, const char *path, int sx, int sy, @@ -157,8 +159,29 @@ static void file_draw_icon(uiBlock *block, UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path)); if (drag) { - /* path is no more static, cannot give it directly to but... */ - UI_but_drag_set_path(but, BLI_strdup(path), true); + /* TODO duplicated from file_draw_preview(). */ + ID *id; + + if ((id = filelist_file_get_id(file))) { + UI_but_drag_set_id(but, id); + } + else if (file->typeflag & FILE_TYPE_ASSET) { + ImBuf *preview_image = filelist_file_getimage(file); + char blend_path[FILE_MAX_LIBEXTRA]; + if (BLO_library_path_explode(path, blend_path, NULL, NULL)) { + UI_but_drag_set_asset(but, + file->name, + BLI_strdup(blend_path), + file->blentype, + icon, + preview_image, + UI_DPI_FAC); + } + } + else { + /* path is no more static, cannot give it directly to but... */ + UI_but_drag_set_path(but, BLI_strdup(path), true); + } } } @@ -200,6 +223,65 @@ static void file_draw_string(int sx, }); } +/** + * \param r_sx, r_sy: The lower right corner of the last line drawn. AKA the cursor position on + * completion. + */ +static void file_draw_string_multiline(int sx, + int sy, + const char *string, + int wrap_width, + int line_height, + const uchar text_col[4], + int *r_sx, + int *r_sy) +{ + rcti rect; + + if (string[0] == '\0' || wrap_width < 1) { + return; + } + + const uiStyle *style = UI_style_get(); + int font_id = style->widgetlabel.uifont_id; + int len = strlen(string); + + rctf textbox; + BLF_wordwrap(font_id, wrap_width); + BLF_enable(font_id, BLF_WORD_WRAP); + BLF_boundbox(font_id, string, len, &textbox); + BLF_disable(font_id, BLF_WORD_WRAP); + + /* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict + * (for buttons it works) */ + rect.xmin = sx; + rect.xmax = sx + wrap_width; + /* Need to increase the clipping rect by one more line, since the #UI_fontstyle_draw_ex() will + * actually start drawing at (ymax - line-height). */ + rect.ymin = sy - round_fl_to_int(BLI_rctf_size_y(&textbox)) - line_height; + rect.ymax = sy; + + struct ResultBLF result; + UI_fontstyle_draw_ex(&style->widget, + &rect, + string, + text_col, + &(struct uiFontStyleDraw_Params){ + .align = UI_STYLE_TEXT_LEFT, + .word_wrap = true, + }, + len, + NULL, + NULL, + &result); + if (r_sx) { + *r_sx = result.width; + } + if (r_sy) { + *r_sy = rect.ymin + line_height; + } +} + void file_calc_previews(const bContext *C, ARegion *region) { SpaceFile *sfile = CTX_wm_space_file(C); @@ -210,6 +292,7 @@ void file_calc_previews(const bContext *C, ARegion *region) } static void file_draw_preview(uiBlock *block, + const FileDirEntry *file, const char *path, int sx, int sy, @@ -218,7 +301,6 @@ static void file_draw_preview(uiBlock *block, const int icon, FileLayout *layout, const bool is_icon, - const int typeflags, const bool drag, const bool dimmed, const bool is_link) @@ -232,7 +314,7 @@ static void file_draw_preview(uiBlock *block, float scale; int ex, ey; bool show_outline = !is_icon && - (typeflags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER)); + (file->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER)); BLI_assert(imb != NULL); @@ -273,14 +355,14 @@ static void file_draw_preview(uiBlock *block, float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; if (is_icon) { - if (typeflags & FILE_TYPE_DIR) { + if (file->typeflag & FILE_TYPE_DIR) { UI_GetThemeColor4fv(TH_ICON_FOLDER, col); } else { UI_GetThemeColor4fv(TH_TEXT, col); } } - else if (typeflags & FILE_TYPE_FTFONT) { + else if (file->typeflag & FILE_TYPE_FTFONT) { UI_GetThemeColor4fv(TH_TEXT, col); } @@ -288,7 +370,7 @@ static void file_draw_preview(uiBlock *block, col[3] *= 0.3f; } - if (!is_icon && typeflags & FILE_TYPE_BLENDERLIB) { + if (!is_icon && file->typeflag & FILE_TYPE_BLENDERLIB) { /* Datablock preview images use premultiplied alpha. */ GPU_blend(GPU_BLEND_ALPHA_PREMULT); } @@ -324,7 +406,7 @@ static void file_draw_preview(uiBlock *block, icon_color[2] = 255; } icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); - icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f)); + icon_y = yco + (ey / 2.0f) - (icon_size * ((file->typeflag & FILE_TYPE_DIR) ? 0.78f : 0.75f)); UI_icon_draw_ex( icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); } @@ -346,13 +428,13 @@ static void file_draw_preview(uiBlock *block, /* Link to folder or non-previewed file. */ uchar icon_color[4]; UI_GetThemeColor4ubv(TH_BACK, icon_color); - icon_x = xco + ((typeflags & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx; - icon_y = yco + ((typeflags & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy; + icon_x = xco + ((file->typeflag & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx; + icon_y = yco + ((file->typeflag & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy; UI_icon_draw_ex( icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false); } } - else if (icon && !is_icon && !(typeflags & FILE_TYPE_FTFONT)) { + else if (icon && !is_icon && !(file->typeflag & FILE_TYPE_FTFONT)) { /* Smaller, fainter icon at bottom-left for preview image thumbnail, but not for fonts. */ float icon_x, icon_y; const uchar dark[4] = {0, 0, 0, 255}; @@ -385,8 +467,22 @@ static void file_draw_preview(uiBlock *block, /* dragregion */ if (drag) { + ID *id; + + if ((id = filelist_file_get_id(file))) { + UI_but_drag_set_id(but, id); + } /* path is no more static, cannot give it directly to but... */ - UI_but_drag_set_image(but, BLI_strdup(path), icon, imb, scale, true); + else if (file->typeflag & FILE_TYPE_ASSET) { + char blend_path[FILE_MAX_LIBEXTRA]; + if (BLO_library_path_explode(path, blend_path, NULL, NULL)) { + UI_but_drag_set_asset( + but, file->name, BLI_strdup(blend_path), file->blentype, icon, imb, scale); + } + } + else { + UI_but_drag_set_image(but, BLI_strdup(path), icon, imb, scale, true); + } } GPU_blend(GPU_BLEND_NONE); @@ -400,11 +496,12 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); ARegion *region = CTX_wm_region(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - BLI_join_dirfile(orgname, sizeof(orgname), sfile->params->dir, oldname); - BLI_strncpy(filename, sfile->params->renamefile, sizeof(filename)); + BLI_join_dirfile(orgname, sizeof(orgname), params->dir, oldname); + BLI_strncpy(filename, params->renamefile, sizeof(filename)); BLI_filename_make_safe(filename); - BLI_join_dirfile(newname, sizeof(newname), sfile->params->dir, filename); + BLI_join_dirfile(newname, sizeof(newname), params->dir, filename); if (!STREQ(orgname, newname)) { if (!BLI_exists(newname)) { @@ -415,8 +512,8 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) } else { /* If rename is successful, scroll to newly renamed entry. */ - BLI_strncpy(sfile->params->renamefile, filename, sizeof(sfile->params->renamefile)); - sfile->params->rename_flag = FILE_PARAMS_RENAME_POSTSCROLL_PENDING; + BLI_strncpy(params->renamefile, filename, sizeof(params->renamefile)); + params->rename_flag = FILE_PARAMS_RENAME_POSTSCROLL_PENDING; if (sfile->smoothscroll_timer != NULL) { WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); @@ -688,7 +785,7 @@ static void draw_details_columns(const FileSelectParams *params, void file_draw_list(const bContext *C, ARegion *region) { SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileLayout *layout = ED_fileselect_get_layout(sfile, region); View2D *v2d = ®ion->v2d; struct FileList *files = sfile->files; @@ -820,6 +917,7 @@ void file_draw_list(const bContext *C, ARegion *region) } file_draw_preview(block, + file, path, sx, sy, @@ -828,13 +926,13 @@ void file_draw_list(const bContext *C, ARegion *region) icon, layout, is_icon, - file->typeflag, do_drag, is_hidden, is_link); } else { file_draw_icon(block, + file, path, sx, sy - layout->tile_border_y, @@ -847,26 +945,25 @@ void file_draw_list(const bContext *C, ARegion *region) } if (file_selflag & FILE_SEL_EDITING) { - uiBut *but; const short width = (params->display == FILE_IMGDISPLAY) ? textwidth : layout->attribute_columns[COLUMN_NAME].width - ATTRIBUTE_COLUMN_PADDING; - but = uiDefBut(block, - UI_BTYPE_TEXT, - 1, - "", - sx + icon_ofs, - sy - layout->tile_h - 0.15f * UI_UNIT_X, - width - icon_ofs, - textheight, - sfile->params->renamefile, - 1.0f, - (float)sizeof(sfile->params->renamefile), - 0, - 0, - ""); + uiBut *but = uiDefBut(block, + UI_BTYPE_TEXT, + 1, + "", + sx + icon_ofs, + sy - layout->tile_h - 0.15f * UI_UNIT_X, + width - icon_ofs, + textheight, + params->renamefile, + 1.0f, + (float)sizeof(params->renamefile), + 0, + 0, + ""); UI_but_func_rename_set(but, renamebutton_cb, file); UI_but_flag_enable(but, UI_BUT_NO_UTF8); /* allow non utf8 names */ UI_but_flag_disable(but, UI_BUT_UNDO); @@ -906,3 +1003,66 @@ void file_draw_list(const bContext *C, ARegion *region) layout->curr_size = params->thumbnail_size; } + +static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion *region) +{ + const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); + + char library_ui_path[PATH_MAX]; + file_path_to_ui_path(asset_params->base_params.dir, library_ui_path, sizeof(library_ui_path)); + + uchar text_col[4]; + uchar text_alert_col[4]; + UI_GetThemeColor4ubv(TH_TEXT, text_col); + UI_GetThemeColor4ubv(TH_REDALERT, text_alert_col); + + const View2D *v2d = ®ion->v2d; + const int pad = sfile->layout->tile_border_x; + const int width = BLI_rctf_size_x(&v2d->tot) - (2 * pad); + const int line_height = sfile->layout->textheight; + int sx = v2d->tot.xmin + pad; + /* For some reason no padding needed. */ + int sy = v2d->tot.ymax; + + { + const char *message = TIP_("Library not found"); + const int draw_string_str_len = strlen(message) + 2 + sizeof(library_ui_path); + char *draw_string = alloca(draw_string_str_len); + BLI_snprintf(draw_string, draw_string_str_len, "%s: %s", message, library_ui_path); + file_draw_string_multiline(sx, sy, draw_string, width, line_height, text_alert_col, NULL, &sy); + } + + /* Next line, but separate it a bit further. */ + sy -= line_height; + + { + UI_icon_draw(sx, sy - UI_UNIT_Y, ICON_INFO); + + const char *suggestion = TIP_( + "Set up the library or edit libraries in the Preferences, File Paths section."); + file_draw_string_multiline( + sx + UI_UNIT_X, sy, suggestion, width - UI_UNIT_X, line_height, text_col, NULL, NULL); + } +} + +/** + * Draw a string hint if the file list is invalid. + * \return true if the list is invalid and a hint was drawn. + */ +bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region) +{ + FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); + /* Only for asset browser. */ + if (!ED_fileselect_is_asset_browser(sfile)) { + return false; + } + /* Check if the library exists. */ + if ((asset_params->asset_library.type == FILE_ASSET_LIBRARY_LOCAL) || + filelist_is_dir(sfile->files, asset_params->base_params.dir)) { + return false; + } + + file_draw_invalid_library_hint(sfile, region); + + return true; +} diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index b459c02d9e5..56fb588776e 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -38,6 +38,7 @@ struct View2D; void file_calc_previews(const bContext *C, ARegion *region); void file_draw_list(const bContext *C, ARegion *region); +bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region); void file_draw_check_ex(bContext *C, struct ScrArea *area); void file_draw_check(bContext *C); @@ -90,6 +91,7 @@ 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); /* filesel.c */ +void fileselect_refresh_params(struct SpaceFile *sfile); void fileselect_file_set(SpaceFile *sfile, const int index); bool file_attribute_column_type_enabled(const FileSelectParams *params, FileAttributeColumnType column); @@ -116,3 +118,5 @@ void file_execute_region_panels_register(struct ARegionType *art); /* file_utils.c */ void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int file, rcti *r_bounds); + +void file_path_to_ui_path(const char *path, char *r_pathi, int max_size); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 93367ad3d3c..88dd82bb9ea 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -40,6 +40,7 @@ # include "BLI_winstuff.h" #endif +#include "ED_asset.h" #include "ED_fileselect.h" #include "ED_screen.h" #include "ED_select_utils.h" @@ -188,7 +189,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) Main *bmain = CTX_data_main(C); FileSelect retval = FILE_SELECT_NOTHING; SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); int numfiles = filelist_files_ensure(sfile->files); const FileDirEntry *file; @@ -302,10 +303,10 @@ static FileSelect file_select( bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen) { SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileSelect retval = FILE_SELECT_NOTHING; FileSelection sel = file_selection_get(C, rect, fill); /* get the selection */ - const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : - CHECK_ALL; + const FileCheckType check_type = (params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL; /* flag the files as selected in the filelist */ filelist_entries_select_index_range_set( @@ -325,7 +326,7 @@ static FileSelect file_select( } if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) { - sfile->params->active_file = -1; + params->active_file = -1; } else if (sel.last >= 0) { ARegion *region = CTX_wm_region(C); @@ -390,7 +391,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve { ARegion *region = CTX_wm_region(C); SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileSelection sel; rcti rect; @@ -521,8 +522,9 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } - if (sfile && sfile->params) { - int idx = sfile->params->highlight_file; + const FileSelectParams *params = ED_fileselect_get_active_params(sfile); + if (sfile && params) { + int idx = params->highlight_file; int numfiles = filelist_files_ensure(sfile->files); if ((idx >= 0) && (idx < numfiles)) { @@ -613,7 +615,7 @@ static bool file_walk_select_selection_set(wmWindow *win, const bool extend, const bool fill) { - FileSelectParams *params = sfile->params; + FileSelectParams *params = ED_fileselect_get_active_params(sfile); struct FileList *files = sfile->files; const int last_sel = params->active_file; /* store old value */ int active = active_old; /* could use active_old instead, just for readability */ @@ -804,7 +806,7 @@ static bool file_walk_select_do(bContext *C, static int file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); - FileSelectParams *params = sfile->params; + FileSelectParams *params = ED_fileselect_get_active_params(sfile); const int direction = RNA_enum_get(op->ptr, "direction"); const bool extend = RNA_boolean_get(op->ptr, "extend"); const bool fill = RNA_boolean_get(op->ptr, "fill"); @@ -853,6 +855,7 @@ static int file_select_all_exec(bContext *C, wmOperator *op) { ScrArea *area = CTX_wm_area(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileSelection sel; const int numfiles = filelist_files_ensure(sfile->files); int action = RNA_enum_get(op->ptr, "action"); @@ -870,7 +873,7 @@ static int file_select_all_exec(bContext *C, wmOperator *op) switch (action) { case SEL_SELECT: case SEL_INVERT: { - check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES; + check_type = (params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES; filesel_type = (action == SEL_INVERT) ? FILE_SEL_TOGGLE : FILE_SEL_ADD; break; } @@ -888,11 +891,11 @@ static int file_select_all_exec(bContext *C, wmOperator *op) filelist_entries_select_index_range_set( sfile->files, &sel, filesel_type, FILE_SEL_SELECTED, check_type); - sfile->params->active_file = -1; + params->active_file = -1; if (action != SEL_DESELECT) { for (int i = 0; i < numfiles; i++) { if (filelist_entry_select_index_get(sfile->files, i, check_type)) { - sfile->params->active_file = i; + params->active_file = i; break; } } @@ -928,6 +931,7 @@ void FILE_OT_select_all(wmOperatorType *ot) /* Note we could get rid of this one, but it's used by some addon so... * Does not hurt keeping it around for now. */ +/* TODO disallow bookmark editing in assets mode? */ static int bookmark_select_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -935,8 +939,8 @@ static int bookmark_select_exec(bContext *C, wmOperator *op) PropertyRNA *prop; if ((prop = RNA_struct_find_property(op->ptr, "dir"))) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); char entry[256]; - FileSelectParams *params = sfile->params; RNA_property_string_get(op->ptr, prop, entry); BLI_strncpy(params->dir, entry, sizeof(params->dir)); @@ -963,7 +967,7 @@ void FILE_OT_select_bookmark(wmOperatorType *ot) ot->poll = ED_operator_file_active; /* properties */ - prop = RNA_def_string(ot->srna, "dir", NULL, FILE_MAXDIR, "Dir", ""); + prop = RNA_def_string(ot->srna, "dir", NULL, FILE_MAXDIR, "Directory", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } @@ -978,7 +982,7 @@ static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op)) ScrArea *area = CTX_wm_area(C); SpaceFile *sfile = CTX_wm_space_file(C); struct FSMenu *fsmenu = ED_fsmenu_get(); - struct FileSelectParams *params = ED_fileselect_get_params(sfile); + struct FileSelectParams *params = ED_fileselect_get_active_params(sfile); if (params->dir[0] != '\0') { char name[FILE_MAX]; @@ -1274,7 +1278,7 @@ int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my) } numfiles = filelist_files_ensure(sfile->files); - params = ED_fileselect_get_params(sfile); + params = ED_fileselect_get_active_params(sfile); origfile = params->highlight_file; @@ -1345,20 +1349,21 @@ static int file_column_sort_ui_context_invoke(bContext *C, if (file_attribute_column_header_is_inside( ®ion->v2d, sfile->layout, event->mval[0], event->mval[1])) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); const FileAttributeColumnType column_type = file_attribute_column_type_find_isect( - ®ion->v2d, sfile->params, sfile->layout, event->mval[0]); + ®ion->v2d, params, sfile->layout, event->mval[0]); if (column_type != COLUMN_NONE) { const FileAttributeColumn *column = &sfile->layout->attribute_columns[column_type]; BLI_assert(column->sort_type != FILE_SORT_DEFAULT); - if (sfile->params->sort == column->sort_type) { + if (params->sort == column->sort_type) { /* Already sorting by selected column -> toggle sort invert (three state logic). */ - sfile->params->flag ^= FILE_SORT_INVERT; + params->flag ^= FILE_SORT_INVERT; } else { - sfile->params->sort = column->sort_type; - sfile->params->flag &= ~FILE_SORT_INVERT; + params->sort = column->sort_type; + params->flag &= ~FILE_SORT_INVERT; } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); @@ -1433,10 +1438,11 @@ void FILE_OT_cancel(struct wmOperatorType *ot) void file_sfile_to_operator_ex(Main *bmain, wmOperator *op, SpaceFile *sfile, char *filepath) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); PropertyRNA *prop; /* XXX, not real length */ - BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file); + BLI_join_dirfile(filepath, FILE_MAX, params->dir, params->file); if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) { if (RNA_property_boolean_get(op->ptr, prop)) { @@ -1445,10 +1451,10 @@ void file_sfile_to_operator_ex(Main *bmain, wmOperator *op, SpaceFile *sfile, ch } if ((prop = RNA_struct_find_property(op->ptr, "filename"))) { - RNA_property_string_set(op->ptr, prop, sfile->params->file); + RNA_property_string_set(op->ptr, prop, params->file); } if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { - RNA_property_string_set(op->ptr, prop, sfile->params->dir); + RNA_property_string_set(op->ptr, prop, params->dir); } if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { RNA_property_string_set(op->ptr, prop, filepath); @@ -1479,7 +1485,7 @@ void file_sfile_to_operator_ex(Main *bmain, wmOperator *op, SpaceFile *sfile, ch * files selected */ if (0 == num_files) { RNA_property_collection_add(op->ptr, prop, &itemptr); - RNA_string_set(&itemptr, "name", sfile->params->file); + RNA_string_set(&itemptr, "name", params->file); } } @@ -1500,7 +1506,7 @@ void file_sfile_to_operator_ex(Main *bmain, wmOperator *op, SpaceFile *sfile, ch * directory selected */ if (0 == num_dirs) { RNA_property_collection_add(op->ptr, prop, &itemptr); - RNA_string_set(&itemptr, "name", sfile->params->dir); + RNA_string_set(&itemptr, "name", params->dir); } } } @@ -1514,30 +1520,28 @@ void file_sfile_to_operator(Main *bmain, wmOperator *op, SpaceFile *sfile) void file_operator_to_sfile(Main *bmain, SpaceFile *sfile, wmOperator *op) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); PropertyRNA *prop; /* If neither of the above are set, split the filepath back */ if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { char filepath[FILE_MAX]; RNA_property_string_get(op->ptr, prop, filepath); - BLI_split_dirfile(filepath, - sfile->params->dir, - sfile->params->file, - sizeof(sfile->params->dir), - sizeof(sfile->params->file)); + BLI_split_dirfile( + filepath, params->dir, params->file, sizeof(params->dir), sizeof(params->file)); } else { if ((prop = RNA_struct_find_property(op->ptr, "filename"))) { - RNA_property_string_get(op->ptr, prop, sfile->params->file); + RNA_property_string_get(op->ptr, prop, params->file); } if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { - RNA_property_string_get(op->ptr, prop, sfile->params->dir); + RNA_property_string_get(op->ptr, prop, params->dir); } } /* we could check for relative_path property which is used when converting * in the other direction but doesn't hurt to do this every time */ - BLI_path_abs(sfile->params->dir, BKE_main_blendfile_path(bmain)); + BLI_path_abs(params->dir, BKE_main_blendfile_path(bmain)); /* XXX, files and dirs updates missing, not really so important though */ } @@ -1547,21 +1551,19 @@ void file_operator_to_sfile(Main *bmain, SpaceFile *sfile, wmOperator *op) */ void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); BLI_assert(BLI_exists(filepath)); if (BLI_is_dir(filepath)) { - BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, filepath, sizeof(params->dir)); } else { - if ((sfile->params->flag & FILE_DIRSEL_ONLY) == 0) { - BLI_split_dirfile(filepath, - sfile->params->dir, - sfile->params->file, - sizeof(sfile->params->dir), - sizeof(sfile->params->file)); + if ((params->flag & FILE_DIRSEL_ONLY) == 0) { + BLI_split_dirfile( + filepath, params->dir, params->file, sizeof(params->dir), sizeof(params->file)); } else { - BLI_split_dir_part(filepath, sfile->params->dir, sizeof(sfile->params->dir)); + BLI_split_dir_part(filepath, params->dir, sizeof(params->dir)); } } } @@ -1605,9 +1607,10 @@ void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2)) bool file_draw_check_exists(SpaceFile *sfile) { if (sfile->op) { /* fails on reload */ - if (sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING)) { + const FileSelectParams *params = ED_fileselect_get_active_params(sfile); + if (params && (params->flag & FILE_CHECK_EXISTING)) { char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file); + BLI_join_dirfile(filepath, sizeof(filepath), params->dir, params->file); if (BLI_is_file(filepath)) { return true; } @@ -1628,21 +1631,22 @@ static int file_exec(bContext *C, wmOperator *exec_op) Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); - struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + struct FileDirEntry *file = filelist_file(sfile->files, params->active_file); char filepath[FILE_MAX]; if (file && file->redirection_path) { /* redirection_path is an absolute path that takes precedence - * over using sfile->params->dir + sfile->params->file. */ + * over using params->dir + params->file. */ BLI_split_dirfile(file->redirection_path, - sfile->params->dir, - sfile->params->file, - sizeof(sfile->params->dir), - sizeof(sfile->params->file)); + params->dir, + params->file, + sizeof(params->dir), + sizeof(params->file)); /* Update relpath with redirected filename as well so that the alternative - * combination of sfile->params->dir + relpath remains valid as well. */ + * combination of params->dir + relpath remains valid as well. */ MEM_freeN(file->relpath); - file->relpath = BLI_strdup(sfile->params->file); + file->relpath = BLI_strdup(params->file); } /* directory change */ @@ -1652,12 +1656,12 @@ static int file_exec(bContext *C, wmOperator *exec_op) } if (FILENAME_IS_PARENT(file->relpath)) { - BLI_path_parent_dir(sfile->params->dir); + BLI_path_parent_dir(params->dir); } else { - BLI_path_normalize(BKE_main_blendfile_path(bmain), sfile->params->dir); - BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath); - BLI_path_slash_ensure(sfile->params->dir); + BLI_path_normalize(BKE_main_blendfile_path(bmain), params->dir); + BLI_path_append(params->dir, sizeof(params->dir) - 1, file->relpath); + BLI_path_slash_ensure(params->dir); } ED_file_change_dir(C); } @@ -1685,10 +1689,10 @@ static int file_exec(bContext *C, wmOperator *exec_op) file_sfile_to_operator_ex(bmain, op, sfile, filepath); - if (BLI_exists(sfile->params->dir)) { + if (BLI_exists(params->dir)) { fsmenu_insert_entry(ED_fsmenu_get(), FS_CATEGORY_RECENT, - sfile->params->dir, + params->dir, NULL, ICON_FILE_FOLDER, FS_INSERT_SAVE | FS_INSERT_FIRST); @@ -1792,15 +1796,16 @@ static int file_parent_exec(bContext *C, wmOperator *UNUSED(unused)) { Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - if (BLI_path_parent_dir(sfile->params->dir)) { - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); + if (params) { + if (BLI_path_parent_dir(params->dir)) { + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); ED_file_change_dir(C); - if (sfile->params->recursion_level > 1) { + if (params->recursion_level > 1) { /* Disable 'dirtree' recursion when going up in tree. */ - sfile->params->recursion_level = 0; - filelist_setrecursion(sfile->files, sfile->params->recursion_level); + params->recursion_level = 0; + filelist_setrecursion(sfile->files, params->recursion_level); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -1830,15 +1835,12 @@ void FILE_OT_parent(struct wmOperatorType *ot) static int file_previous_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - if (!sfile->folders_next) { - sfile->folders_next = folderlist_new(); - } - - folderlist_pushdir(sfile->folders_next, sfile->params->dir); - folderlist_popdir(sfile->folders_prev, sfile->params->dir); - folderlist_pushdir(sfile->folders_next, sfile->params->dir); + if (params) { + folderlist_pushdir(sfile->folders_next, params->dir); + folderlist_popdir(sfile->folders_prev, params->dir); + folderlist_pushdir(sfile->folders_next, params->dir); ED_file_change_dir(C); } @@ -1868,16 +1870,13 @@ void FILE_OT_previous(struct wmOperatorType *ot) static int file_next_exec(bContext *C, wmOperator *UNUSED(unused)) { SpaceFile *sfile = CTX_wm_space_file(C); - if (sfile->params) { - if (!sfile->folders_next) { - sfile->folders_next = folderlist_new(); - } - - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); - folderlist_popdir(sfile->folders_next, sfile->params->dir); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + if (params) { + folderlist_pushdir(sfile->folders_prev, params->dir); + folderlist_popdir(sfile->folders_next, params->dir); /* update folders_prev so we can check for it in #folderlist_clear_next() */ - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); + folderlist_pushdir(sfile->folders_prev, params->dir); ED_file_change_dir(C); } @@ -1923,7 +1922,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w /* Due to async nature of file listing, we may execute this code before `file_refresh()` * editing entry is available in our listing, * so we also have to handle switching to rename mode here. */ - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); if ((params->rename_flag & (FILE_PARAMS_RENAME_PENDING | FILE_PARAMS_RENAME_POSTSCROLL_PENDING)) != 0) { file_params_renamefile_activate(sfile, params); @@ -2175,9 +2174,10 @@ static int file_directory_new_exec(bContext *C, wmOperator *op) wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); const bool do_diropen = RNA_boolean_get(op->ptr, "open"); - if (!sfile->params) { + if (!params) { BKE_report(op->reports, RPT_WARNING, "No parent directory given"); return OPERATOR_CANCELLED; } @@ -2193,7 +2193,7 @@ static int file_directory_new_exec(bContext *C, wmOperator *op) if (generate_name) { /* create a new, non-existing folder name */ - if (!new_folder_path(sfile->params->dir, path, name)) { + if (!new_folder_path(params->dir, path, name)) { BKE_report(op->reports, RPT_ERROR, "Could not create new folder name"); return OPERATOR_CANCELLED; } @@ -2226,8 +2226,8 @@ static int file_directory_new_exec(bContext *C, wmOperator *op) /* If we don't enter the directory directly, remember file to jump into editing. */ if (do_diropen == false) { - BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE); - sfile->params->rename_flag = FILE_PARAMS_RENAME_PENDING; + BLI_strncpy(params->renamefile, name, FILE_MAXFILE); + params->rename_flag = FILE_PARAMS_RENAME_PENDING; } /* set timer to smoothly view newly generated file */ @@ -2242,7 +2242,7 @@ static int file_directory_new_exec(bContext *C, wmOperator *op) ED_fileselect_clear(wm, CTX_data_scene(C), sfile); if (do_diropen) { - BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, path, sizeof(params->dir)); ED_file_change_dir(C); } @@ -2284,38 +2284,37 @@ static void file_expand_directory(bContext *C) { Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - if (BLI_path_is_rel(sfile->params->dir)) { + if (params) { + if (BLI_path_is_rel(params->dir)) { /* Use of 'default' folder here is just to avoid an error message on '//' prefix. */ - BLI_path_abs(sfile->params->dir, + BLI_path_abs(params->dir, G.relbase_valid ? BKE_main_blendfile_path(bmain) : BKE_appdir_folder_default()); } - else if (sfile->params->dir[0] == '~') { - char tmpstr[sizeof(sfile->params->dir) - 1]; - BLI_strncpy(tmpstr, sfile->params->dir + 1, sizeof(tmpstr)); - BLI_join_dirfile( - sfile->params->dir, sizeof(sfile->params->dir), BKE_appdir_folder_default(), tmpstr); + else if (params->dir[0] == '~') { + char tmpstr[sizeof(params->dir) - 1]; + BLI_strncpy(tmpstr, params->dir + 1, sizeof(tmpstr)); + BLI_join_dirfile(params->dir, sizeof(params->dir), BKE_appdir_folder_default(), tmpstr); } - else if (sfile->params->dir[0] == '\0') + else if (params->dir[0] == '\0') #ifndef WIN32 { - sfile->params->dir[0] = '/'; - sfile->params->dir[1] = '\0'; + params->dir[0] = '/'; + params->dir[1] = '\0'; } #else { - BLI_windows_get_default_root_dir(sfile->params->dir); + BLI_windows_get_default_root_dir(params->dir); } /* change "C:" --> "C:\", T28102. */ - else if ((isalpha(sfile->params->dir[0]) && (sfile->params->dir[1] == ':')) && - (sfile->params->dir[2] == '\0')) { - sfile->params->dir[2] = '\\'; - sfile->params->dir[3] = '\0'; + else if ((isalpha(params->dir[0]) && (params->dir[1] == ':')) && (params->dir[2] == '\0')) { + params->dir[2] = '\\'; + params->dir[3] = '\0'; } - else if (BLI_path_is_unc(sfile->params->dir)) { - BLI_path_normalize_unc(sfile->params->dir, FILE_MAX_LIBEXTRA); + else if (BLI_path_is_unc(params->dir)) { + BLI_path_normalize_unc(params->dir, FILE_MAX_LIBEXTRA); } #endif } @@ -2343,46 +2342,44 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN { Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - char old_dir[sizeof(sfile->params->dir)]; + if (params) { + char old_dir[sizeof(params->dir)]; - BLI_strncpy(old_dir, sfile->params->dir, sizeof(old_dir)); + BLI_strncpy(old_dir, params->dir, sizeof(old_dir)); file_expand_directory(C); /* special case, user may have pasted a filepath into the directory */ - if (!filelist_is_dir(sfile->files, sfile->params->dir)) { + if (!filelist_is_dir(sfile->files, params->dir)) { char tdir[FILE_MAX_LIBEXTRA]; char *group, *name; - if (BLI_is_file(sfile->params->dir)) { - char path[sizeof(sfile->params->dir)]; - BLI_strncpy(path, sfile->params->dir, sizeof(path)); - BLI_split_dirfile(path, - sfile->params->dir, - sfile->params->file, - sizeof(sfile->params->dir), - sizeof(sfile->params->file)); + if (BLI_is_file(params->dir)) { + char path[sizeof(params->dir)]; + BLI_strncpy(path, params->dir, sizeof(path)); + BLI_split_dirfile( + path, params->dir, params->file, sizeof(params->dir), sizeof(params->file)); } - else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) { + else if (BLO_library_path_explode(params->dir, tdir, &group, &name)) { if (group) { BLI_path_append(tdir, sizeof(tdir), group); } - BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, tdir, sizeof(params->dir)); if (name) { - BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file)); + BLI_strncpy(params->file, name, sizeof(params->file)); } else { - sfile->params->file[0] = '\0'; + params->file[0] = '\0'; } } } - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); - if (filelist_is_dir(sfile->files, sfile->params->dir)) { - if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */ + if (filelist_is_dir(sfile->files, params->dir)) { + if (!STREQ(params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */ /* if directory exists, enter it immediately */ ED_file_change_dir(C); } @@ -2392,10 +2389,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN /* UI_textbutton_activate_but(C, but); */ } #if defined(WIN32) - else if (!can_create_dir(sfile->params->dir)) { + else if (!can_create_dir(params->dir)) { const char *lastdir = folderlist_peeklastdir(sfile->folders_prev); if (lastdir) { - BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, lastdir, sizeof(params->dir)); } } #endif @@ -2405,21 +2402,21 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN /* If we are 'inside' a blend library, we cannot do anything... */ if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) { - BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, lastdir, sizeof(params->dir)); } else { /* if not, ask to create it and enter if confirmed */ wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); - RNA_string_set(&ptr, "directory", sfile->params->dir); + RNA_string_set(&ptr, "directory", params->dir); RNA_boolean_set(&ptr, "open", true); /* Enable confirmation prompt, else it's too easy * to accidentally create new directories. */ RNA_boolean_set(&ptr, "confirm", true); if (lastdir) { - BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, lastdir, sizeof(params->dir)); } WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); @@ -2435,39 +2432,39 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg { Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); uiBut *but = arg_but; char matched_file[FILE_MAX]; - char filepath[sizeof(sfile->params->dir)]; - if (sfile->params) { + if (params) { + char filepath[sizeof(params->dir)]; int matches; matched_file[0] = '\0'; filepath[0] = '\0'; file_expand_directory(C); - matches = file_select_match(sfile, sfile->params->file, matched_file); + matches = file_select_match(sfile, params->file, matched_file); /* *After* file_select_match! */ - BLI_filename_make_safe(sfile->params->file); + BLI_filename_make_safe(params->file); if (matches) { /* replace the pattern (or filename that the user typed in, * with the first selected file of the match */ - BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file)); + BLI_strncpy(params->file, matched_file, sizeof(params->file)); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); } if (matches == 1) { - BLI_join_dirfile( - filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file); + BLI_join_dirfile(filepath, sizeof(params->dir), params->dir, params->file); /* if directory, open it and empty filename field */ if (filelist_is_dir(sfile->files, filepath)) { BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), filepath); - BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); - sfile->params->file[0] = '\0'; + BLI_strncpy(params->dir, filepath, sizeof(params->dir)); + params->file[0] = '\0'; ED_file_change_dir(C); UI_textbutton_activate_but(C, but); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); @@ -2489,9 +2486,10 @@ static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused)) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - sfile->params->flag ^= FILE_HIDE_DOT; + if (params) { + params->flag ^= FILE_HIDE_DOT; ED_fileselect_clear(wm, CTX_data_scene(C), sfile); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -2525,7 +2523,8 @@ static bool file_filenum_poll(bContext *C) return false; } - return sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + return params && (params->flag & FILE_CHECK_EXISTING); } /** @@ -2563,11 +2562,12 @@ static void filenum_newname(char *name, size_t name_size, int add) static int file_filenum_exec(bContext *C, wmOperator *op) { SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); ScrArea *area = CTX_wm_area(C); int inc = RNA_int_get(op->ptr, "increment"); - if (sfile->params && (inc != 0)) { - filenum_newname(sfile->params->file, sizeof(sfile->params->file), inc); + if (params && (inc != 0)) { + filenum_newname(params->file, sizeof(params->file), inc); ED_area_tag_redraw(area); file_draw_check(C); // WM_event_add_notifier(C, NC_WINDOW, NULL); @@ -2606,12 +2606,14 @@ static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool requ if ((require_selected == false) || (filelist_entry_select_get(sfile->files, file, CHECK_ALL) & FILE_SEL_SELECTED)) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + filelist_entry_select_index_set( sfile->files, file_idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); - BLI_strncpy(sfile->params->renamefile, file->relpath, FILE_MAXFILE); + BLI_strncpy(params->renamefile, file->relpath, FILE_MAXFILE); /* We can skip the pending state, * as we can directly set FILE_SEL_EDITING on the expected entry here. */ - sfile->params->rename_flag = FILE_PARAMS_RENAME_ACTIVE; + params->rename_flag = FILE_PARAMS_RENAME_ACTIVE; } } } @@ -2620,9 +2622,10 @@ static int file_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent { ScrArea *area = CTX_wm_area(C); SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - file_rename_state_activate(sfile, sfile->params->active_file, true); + if (params) { + file_rename_state_activate(sfile, params->active_file, true); ED_area_tag_redraw(area); } @@ -2633,9 +2636,10 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op)) { ScrArea *area = CTX_wm_area(C); SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - file_rename_state_activate(sfile, sfile->params->highlight_file, false); + if (params) { + file_rename_state_activate(sfile, params->highlight_file, false); ED_area_tag_redraw(area); } @@ -2665,8 +2669,9 @@ static bool file_delete_poll(bContext *C) { bool poll = ED_operator_file_active(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile && sfile->params) { + if (sfile && params) { char dir[FILE_MAX_LIBEXTRA]; int numfiles = filelist_files_ensure(sfile->files); int i; @@ -2691,10 +2696,34 @@ static bool file_delete_poll(bContext *C) return poll; } +static bool file_delete_single(const FileSelectParams *params, + FileDirEntry *file, + const char **r_error_message) +{ + if (file->typeflag & FILE_TYPE_ASSET) { + ID *id = filelist_file_get_id(file); + if (!id) { + *r_error_message = "File is not a local data-block asset."; + return false; + } + ED_asset_clear_id(id); + } + else { + char str[FILE_MAX]; + BLI_join_dirfile(str, sizeof(str), params->dir, file->relpath); + if (BLI_delete_soft(str, r_error_message) != 0 || BLI_exists(str)) { + return false; + } + } + + return true; +} + static int file_delete_exec(bContext *C, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); int numfiles = filelist_files_ensure(sfile->files); const char *error_message = NULL; @@ -2703,9 +2732,7 @@ static int file_delete_exec(bContext *C, wmOperator *op) for (int i = 0; i < numfiles; i++) { if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) { FileDirEntry *file = filelist_file(sfile->files, i); - char str[FILE_MAX]; - BLI_join_dirfile(str, sizeof(str), sfile->params->dir, file->relpath); - if (BLI_delete_soft(str, &error_message) != 0 || BLI_exists(str)) { + if (!file_delete_single(params, file, &error_message)) { report_error = true; } } @@ -2751,12 +2778,20 @@ void FILE_OT_delete(struct wmOperatorType *ot) static int file_start_filter_exec(bContext *C, wmOperator *UNUSED(op)) { ScrArea *area = CTX_wm_area(C); - ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_UI); - SpaceFile *sf = CTX_wm_space_file(C); + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); ARegion *region_ctx = CTX_wm_region(C); - CTX_wm_region_set(C, region); - UI_textbutton_activate_rna(C, region, sf->params, "filter_search"); + + if (area) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { + CTX_wm_region_set(C, region); + if (UI_textbutton_activate_rna(C, region, params, "filter_search")) { + break; + } + } + } + CTX_wm_region_set(C, region_ctx); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index 22d206c0a70..411f99cc3b4 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -132,7 +132,7 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *panel) { bScreen *screen = CTX_wm_screen(C); SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); uiBlock *block = uiLayoutGetBlock(panel->layout); uiBut *but; uiLayout *row; @@ -180,11 +180,16 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *panel) UI_but_funcN_set(but, file_filename_enter_handle, NULL, but); if (params->flag & FILE_CHECK_EXISTING) { - but_extra_rna_ptr = UI_but_extra_operator_icon_add( + uiButExtraOpIcon *extra_icon; + + extra_icon = UI_but_extra_operator_icon_add( but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_REMOVE); + but_extra_rna_ptr = UI_but_extra_operator_icon_opptr_get(extra_icon); RNA_int_set(but_extra_rna_ptr, "increment", -1); - but_extra_rna_ptr = UI_but_extra_operator_icon_add( + + extra_icon = UI_but_extra_operator_icon_add( but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_ADD); + but_extra_rna_ptr = UI_but_extra_operator_icon_opptr_get(extra_icon); RNA_int_set(but_extra_rna_ptr, "increment", 1); } diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c index 452f2f704cf..9d85996c559 100644 --- a/source/blender/editors/space_file/file_utils.c +++ b/source/blender/editors/space_file/file_utils.c @@ -18,12 +18,14 @@ * \ingroup spfile */ +#include "BLI_fileops.h" #include "BLI_listbase.h" +#include "BLI_path_util.h" #include "BLI_rect.h" - -#include "BLO_readfile.h" +#include "BLI_string.h" #include "BKE_context.h" +#include "BLO_readfile.h" #include "ED_fileselect.h" #include "ED_screen.h" @@ -44,3 +46,14 @@ void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int fil ymax - layout->tile_h - layout->tile_border_y, ymax); } + +/** + * If \a path leads to a .blend, remove the trailing slash (if needed). + */ +void file_path_to_ui_path(const char *path, char *r_path, int max_size) +{ + char tmp_path[PATH_MAX]; + BLI_strncpy(tmp_path, path, sizeof(tmp_path)); + BLI_path_slash_rstrip(tmp_path); + BLI_strncpy(r_path, BLO_has_bfile_extension(tmp_path) ? tmp_path : path, max_size); +} diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 9e51b6ca4ba..d66219c7549 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -53,13 +53,18 @@ # include "BLI_winstuff.h" #endif +#include "BKE_asset.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_idtype.h" +#include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_main_idmap.h" +#include "BKE_preferences.h" #include "BLO_readfile.h" +#include "DNA_asset_types.h" #include "DNA_space_types.h" #include "ED_datafiles.h" @@ -82,6 +87,8 @@ #include "filelist.h" +#define FILEDIR_NBR_ENTRIES_UNSET -1 + /* ----------------- FOLDERLIST (previous/next) -------------- */ typedef struct FolderList { @@ -89,12 +96,6 @@ typedef struct FolderList { char *foldername; } FolderList; -ListBase *folderlist_new(void) -{ - ListBase *p = MEM_callocN(sizeof(*p), __func__); - return p; -} - void folderlist_popdir(struct ListBase *folderlist, char *dir) { const char *prev_dir; @@ -117,6 +118,10 @@ void folderlist_popdir(struct ListBase *folderlist, char *dir) void folderlist_pushdir(ListBase *folderlist, const char *dir) { + if (!dir[0]) { + return; + } + struct FolderList *folder, *previous_folder; previous_folder = folderlist->last; @@ -149,17 +154,18 @@ const char *folderlist_peeklastdir(ListBase *folderlist) int folderlist_clear_next(struct SpaceFile *sfile) { + const FileSelectParams *params = ED_fileselect_get_active_params(sfile); struct FolderList *folder; /* if there is no folder_next there is nothing we can clear */ - if (!sfile->folders_next) { + if (BLI_listbase_is_empty(sfile->folders_next)) { return 0; } /* if previous_folder, next_folder or refresh_folder operators are executed * it doesn't clear folder_next */ folder = sfile->folders_prev->last; - if ((!folder) || (BLI_path_cmp(folder->foldername, sfile->params->dir) == 0)) { + if ((!folder) || (BLI_path_cmp(folder->foldername, params->dir) == 0)) { return 0; } @@ -179,23 +185,79 @@ void folderlist_free(ListBase *folderlist) } } -ListBase *folderlist_duplicate(ListBase *folderlist) +static ListBase folderlist_duplicate(ListBase *folderlist) { + ListBase folderlistn = {NULL}; - if (folderlist) { - ListBase *folderlistn = MEM_callocN(sizeof(*folderlistn), __func__); - FolderList *folder; + BLI_duplicatelist(&folderlistn, folderlist); + + for (FolderList *folder = folderlistn.first; folder; folder = folder->next) { + folder->foldername = MEM_dupallocN(folder->foldername); + } + return folderlistn; +} - BLI_duplicatelist(folderlistn, folderlist); +/* ----------------- Folder-History (wraps/owns file list above) -------------- */ - for (folder = folderlistn->first; folder; folder = folder->next) { - folder->foldername = MEM_dupallocN(folder->foldername); +static FileFolderHistory *folder_history_find(const SpaceFile *sfile, eFileBrowse_Mode browse_mode) +{ + LISTBASE_FOREACH (FileFolderHistory *, history, &sfile->folder_histories) { + if (history->browse_mode == browse_mode) { + return history; } - return folderlistn; } + return NULL; } +void folder_history_list_ensure_for_active_browse_mode(SpaceFile *sfile) +{ + FileFolderHistory *history = folder_history_find(sfile, sfile->browse_mode); + + if (!history) { + history = MEM_callocN(sizeof(*history), __func__); + history->browse_mode = sfile->browse_mode; + BLI_addtail(&sfile->folder_histories, history); + } + + sfile->folders_next = &history->folders_next; + sfile->folders_prev = &history->folders_prev; +} + +static void folder_history_entry_free(SpaceFile *sfile, FileFolderHistory *history) +{ + if (sfile->folders_prev == &history->folders_prev) { + sfile->folders_prev = NULL; + } + if (sfile->folders_next == &history->folders_next) { + sfile->folders_next = NULL; + } + folderlist_free(&history->folders_prev); + folderlist_free(&history->folders_next); + BLI_freelinkN(&sfile->folder_histories, history); +} + +void folder_history_list_free(SpaceFile *sfile) +{ + LISTBASE_FOREACH_MUTABLE (FileFolderHistory *, history, &sfile->folder_histories) { + folder_history_entry_free(sfile, history); + } +} + +ListBase folder_history_list_duplicate(ListBase *listbase) +{ + ListBase histories = {NULL}; + + LISTBASE_FOREACH (FileFolderHistory *, history, listbase) { + FileFolderHistory *history_new = MEM_dupallocN(history); + history_new->folders_prev = folderlist_duplicate(&history->folders_prev); + history_new->folders_next = folderlist_duplicate(&history->folders_next); + BLI_addtail(&histories, history_new); + } + + return histories; +} + /* ------------------FILELIST------------------------ */ typedef struct FileListInternEntry { @@ -215,6 +277,24 @@ typedef struct FileListInternEntry { /** not strictly needed, but used during sorting, avoids to have to recompute it there... */ char *name; + /** + * This is data from the current main, represented by this file. It's crucial that this is + * updated correctly on undo, redo and file reading (without UI). The space is responsible to + * take care of that. + */ + struct { + /** When showing local IDs (FILE_MAIN, FILE_MAIN_ASSET), the ID this file entry represents. */ + ID *id; + + /* For the few file types that have the preview already in memory. For others, there's delayed + * preview reading from disk. Non-owning pointer. */ + PreviewImage *preview_image; + } local_data; + + /** When the file represents an asset read from another file, it is stored here. + * Owning pointer. */ + AssetMetaData *imported_asset_data; + /** Defined in BLI_fileops.h */ eFileAttributes attributes; BLI_stat_t st; @@ -266,7 +346,11 @@ typedef struct FileListEntryPreview { char path[FILE_MAX]; uint flags; int index; - ImBuf *img; + /* Some file types load the memory from runtime data, not from disk. We just wait until it's done + * generating (BKE_previewimg_is_finished()). */ + PreviewImage *in_memory_preview; + + int icon_id; } FileListEntryPreview; /* Dummy wrapper around FileListEntryPreview to ensure we do not access freed memory when freeing @@ -289,11 +373,16 @@ enum { FLF_HIDE_DOT = 1 << 1, FLF_HIDE_PARENT = 1 << 2, FLF_HIDE_LIB_DIR = 1 << 3, + FLF_ASSETS_ONLY = 1 << 4, }; typedef struct FileList { FileDirEntryArr filelist; + eFileSelectType type; + /* The library this list was created for. Stored here so we know when to re-read. */ + FileSelectAssetLibraryUID *asset_library; + short flags; short sort; @@ -323,10 +412,13 @@ typedef struct FileList { bool (*checkdirf)(struct FileList *, char *, const bool); /* Fill filelist (to be called by read job). */ - void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); + void (*read_jobf)( + Main *, struct FileList *, const char *, short *, short *, float *, ThreadMutex *); /* Filter an entry of current filelist. */ bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *); + + short tags; /* FileListTags */ } FileList; /* FileList.flags */ @@ -339,6 +431,14 @@ enum { FL_SORT_INVERT = 1 << 5, }; +/* FileList.tags */ +enum FileListTags { + /** The file list has references to main data (IDs) and needs special care. */ + FILELIST_TAGS_USES_MAIN_DATA = (1 << 0), + /** The file list type is not thread-safe. */ + FILELIST_TAGS_NO_THREADS = (1 << 2), +}; + #define SPECIAL_IMG_SIZE 256 #define SPECIAL_IMG_ROWS 1 #define SPECIAL_IMG_COLS 7 @@ -356,24 +456,34 @@ enum { static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX]; -static void filelist_readjob_main(FileList *filelist, +static void filelist_readjob_main(Main *current_main, + FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock); -static void filelist_readjob_lib(FileList *filelist, +static void filelist_readjob_lib(Main *current_main, + FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock); -static void filelist_readjob_dir(FileList *filelist, +static void filelist_readjob_dir(Main *current_main, + FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock); +static void filelist_readjob_main_assets(Main *current_main, + FileList *filelist, + const char *main_name, + short *stop, + short *do_update, + float *progress, + ThreadMutex *lock); /* helper, could probably go in BKE actually? */ static int groupname_to_code(const char *group); @@ -629,7 +739,7 @@ void filelist_setsorting(struct FileList *filelist, const short sort, bool inver /* ********** Filter helpers ********** */ /* True if filename is meant to be hidden, eg. starting with period. */ -static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *file) +static bool is_hidden_dot_filename(const char *filename, const FileListInternEntry *file) { if (filename[0] == '.' && !ELEM(filename[1], '.', '\0')) { return true; /* ignore .file */ @@ -670,8 +780,8 @@ static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *fi /* True if should be hidden, based on current filtering. */ static bool is_filtered_hidden(const char *filename, - FileListFilter *filter, - FileListInternEntry *file) + const FileListFilter *filter, + const FileListInternEntry *file) { if ((filename[0] == '.') && (filename[1] == '\0')) { return true; /* Ignore . */ @@ -693,6 +803,11 @@ static bool is_filtered_hidden(const char *filename, return true; } #endif + /* For data-blocks (but not the group directories), check the asset-only filter. */ + if (!(file->typeflag & FILE_TYPE_DIR) && (file->typeflag & FILE_TYPE_BLENDERLIB) && + (filter->flags & FLF_ASSETS_ONLY) && !(file->typeflag & FILE_TYPE_ASSET)) { + return true; + } return false; } @@ -736,51 +851,61 @@ static bool is_filtered_file(FileListInternEntry *file, return is_filtered; } -static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) +static bool is_filtered_id_file(const FileListInternEntry *file, + const char *id_group, + const char *name, + const FileListFilter *filter) { - bool is_filtered; - char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; - - BLI_join_dirfile(path, sizeof(path), root, file->relpath); - - if (BLO_library_path_explode(path, dir, &group, &name)) { - is_filtered = !is_filtered_hidden(file->relpath, filter, file); - if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { - /* We only check for types if some type are enabled in filtering. */ - if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & - (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; - } - } - else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { - is_filtered = false; - } + bool is_filtered = !is_filtered_hidden(file->relpath, filter, file); + if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { + /* We only check for types if some type are enabled in filtering. */ + if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) { + if (file->typeflag & FILE_TYPE_DIR) { + if (file->typeflag & + (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + is_filtered = false; } } - if (is_filtered && group) { - if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { + else { + if (!(filter->filter & FILE_TYPE_FOLDER)) { is_filtered = false; } - else { - uint64_t filter_id = groupname_to_filter_id(group); - if (!(filter_id & filter->filter_id)) { - is_filtered = false; - } - } } } - /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */ - if (is_filtered && (filter->filter_search[0] != '\0')) { - if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { + if (is_filtered && id_group) { + if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { is_filtered = false; } + else { + uint64_t filter_id = groupname_to_filter_id(id_group); + if (!(filter_id & filter->filter_id)) { + is_filtered = false; + } + } + } + } + /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */ + if (is_filtered && (filter->filter_search[0] != '\0')) { + if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { + is_filtered = false; } } } + + return is_filtered; +} + +static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) +{ + bool is_filtered; + char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; + + BLI_join_dirfile(path, sizeof(path), root, file->relpath); + + if (BLO_library_path_explode(path, dir, &group, &name)) { + is_filtered = is_filtered_id_file(file, group, name, filter); + } else { is_filtered = is_filtered_file(file, root, filter); } @@ -795,6 +920,14 @@ static bool is_filtered_main(FileListInternEntry *file, return !is_filtered_hidden(file->relpath, filter, file); } +static bool is_filtered_main_assets(FileListInternEntry *file, + const char *UNUSED(dir), + FileListFilter *filter) +{ + /* "Filtered" means *not* being filtered out... So return true if the file should be visible. */ + return is_filtered_id_file(file, file->relpath, file->name, filter); +} + static void filelist_filter_clear(FileList *filelist) { filelist->flags |= FL_NEED_FILTERING; @@ -806,7 +939,7 @@ void filelist_filter(FileList *filelist) const int num_files = filelist->filelist.nbr_entries; FileListInternEntry **filtered_tmp, *file; - if (filelist->filelist.nbr_entries == 0) { + if (ELEM(filelist->filelist.nbr_entries, FILEDIR_NBR_ENTRIES_UNSET, 0)) { return; } @@ -857,6 +990,7 @@ void filelist_setfilter_options(FileList *filelist, const bool hide_parent, const uint64_t filter, const uint64_t filter_id, + const bool filter_assets_only, const char *filter_glob, const char *filter_search) { @@ -874,6 +1008,10 @@ void filelist_setfilter_options(FileList *filelist, filelist->filter_data.flags ^= FLF_HIDE_PARENT; update = true; } + if (((filelist->filter_data.flags & FLF_ASSETS_ONLY) != 0) != (filter_assets_only != 0)) { + filelist->filter_data.flags ^= FLF_ASSETS_ONLY; + update = true; + } if (filelist->filter_data.filter != filter) { filelist->filter_data.filter = filter; update = true; @@ -902,6 +1040,54 @@ void filelist_setfilter_options(FileList *filelist, } } +/** + * Checks two libraries for equality. + * \return True if the libraries match. + */ +static bool filelist_compare_asset_libraries(const FileSelectAssetLibraryUID *library_a, + const FileSelectAssetLibraryUID *library_b) +{ + if (library_a->type != library_b->type) { + return false; + } + if (library_a->type == FILE_ASSET_LIBRARY_CUSTOM) { + /* Don't only check the index, also check that it's valid. */ + bUserAssetLibrary *library_ptr_a = BKE_preferences_asset_library_find_from_index( + &U, library_a->custom_library_index); + return (library_ptr_a != NULL) && + (library_a->custom_library_index == library_b->custom_library_index); + } + + return true; +} + +/** + * \param asset_library: May be NULL to unset the library. + */ +void filelist_setlibrary(FileList *filelist, const FileSelectAssetLibraryUID *asset_library) +{ + /* Unset if needed. */ + if (!asset_library) { + if (filelist->asset_library) { + MEM_SAFE_FREE(filelist->asset_library); + filelist->flags |= FL_FORCE_RESET; + } + return; + } + + if (!filelist->asset_library) { + filelist->asset_library = MEM_mallocN(sizeof(*filelist->asset_library), + "filelist asset library"); + *filelist->asset_library = *asset_library; + + filelist->flags |= FL_FORCE_RESET; + } + else if (!filelist_compare_asset_libraries(filelist->asset_library, asset_library)) { + *filelist->asset_library = *asset_library; + filelist->flags |= FL_FORCE_RESET; + } +} + /* ********** Icon/image helpers ********** */ void filelist_init_icons(void) @@ -959,7 +1145,12 @@ ImBuf *filelist_getimage(struct FileList *filelist, const int index) { FileDirEntry *file = filelist_geticon_get_file(filelist, index); - return file->image; + return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : NULL; +} + +ImBuf *filelist_file_getimage(const FileDirEntry *file) +{ + return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : NULL; } static ImBuf *filelist_geticon_image_ex(FileDirEntry *file) @@ -987,12 +1178,12 @@ ImBuf *filelist_geticon_image(struct FileList *filelist, const int index) return filelist_geticon_image_ex(file); } -static int filelist_geticon_ex(FileDirEntry *file, +static int filelist_geticon_ex(const FileDirEntry *file, const char *root, const bool is_main, const bool ignore_libdir) { - const int typeflag = file->typeflag; + const eFileSel_File_Types typeflag = file->typeflag; if ((typeflag & FILE_TYPE_DIR) && !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) { @@ -1026,7 +1217,7 @@ static int filelist_geticon_ex(FileDirEntry *file, if (file->redirection_path) { target = file->redirection_path; } - else { + else if (root) { BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); BLI_path_slash_ensure(fullpath); } @@ -1110,6 +1301,12 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m return filelist_geticon_ex(file, filelist->filelist.root, is_main, false); } +int ED_file_icon(const FileDirEntry *file) +{ + return file->preview_icon_id ? file->preview_icon_id : + filelist_geticon_ex(file, NULL, false, false); +} + /* ********** Main ********** */ static void parent_dir_until_exists_or_default_root(char *dir) @@ -1159,6 +1356,14 @@ static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const return filelist_checkdir_lib(filelist, r_dir, do_change); } +static bool filelist_checkdir_main_assets(struct FileList *UNUSED(filelist), + char *UNUSED(r_dir), + const bool UNUSED(do_change)) +{ + /* Main is always valid. */ + return true; +} + static void filelist_entry_clear(FileDirEntry *entry) { if (entry->name) { @@ -1173,8 +1378,9 @@ static void filelist_entry_clear(FileDirEntry *entry) if (entry->redirection_path) { MEM_freeN(entry->redirection_path); } - if (entry->image) { - IMB_freeImBuf(entry->image); + if (entry->preview_icon_id) { + BKE_icon_delete(entry->preview_icon_id); + entry->preview_icon_id = 0; } /* For now, consider FileDirEntryRevision::poin as not owned here, * so no need to do anything about it */ @@ -1231,8 +1437,8 @@ static void filelist_direntryarr_free(FileDirEntryArr *array) #else BLI_assert(BLI_listbase_is_empty(&array->entries)); #endif - array->nbr_entries = 0; - array->nbr_entries_filtered = -1; + array->nbr_entries = FILEDIR_NBR_ENTRIES_UNSET; + array->nbr_entries_filtered = FILEDIR_NBR_ENTRIES_UNSET; array->entry_idx_start = -1; array->entry_idx_end = -1; } @@ -1248,6 +1454,10 @@ static void filelist_intern_entry_free(FileListInternEntry *entry) if (entry->name) { MEM_freeN(entry->name); } + /* If we own the asset-data (it was generated from external file data), free it. */ + if (entry->imported_asset_data) { + BKE_asset_metadata_free(&entry->imported_asset_data); + } MEM_freeN(entry); } @@ -1271,37 +1481,54 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat FileListEntryPreview *preview = preview_taskdata->preview; ThumbSource source = 0; + bool done = false; // printf("%s: Start (%d)...\n", __func__, threadid); - // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - BLI_assert(preview->flags & - (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | - FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)); - - if (preview->flags & FILE_TYPE_IMAGE) { - source = THB_SOURCE_IMAGE; - } - else if (preview->flags & - (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) { - source = THB_SOURCE_BLEND; - } - else if (preview->flags & FILE_TYPE_MOVIE) { - source = THB_SOURCE_MOVIE; - } - else if (preview->flags & FILE_TYPE_FTFONT) { - source = THB_SOURCE_FONT; + 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); + done = true; + } } + else { + // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + BLI_assert(preview->flags & + (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | + FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)); - IMB_thumb_path_lock(preview->path); - /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate in - * case user switch to a bigger preview size. */ - preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source); - IMB_thumb_path_unlock(preview->path); + if (preview->flags & FILE_TYPE_IMAGE) { + source = THB_SOURCE_IMAGE; + } + else if (preview->flags & + (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) { + source = THB_SOURCE_BLEND; + } + else if (preview->flags & FILE_TYPE_MOVIE) { + source = THB_SOURCE_MOVIE; + } + else if (preview->flags & FILE_TYPE_FTFONT) { + source = THB_SOURCE_FONT; + } + + IMB_thumb_path_lock(preview->path); + /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate + * in case user switch to a bigger preview size. */ + ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source); + IMB_thumb_path_unlock(preview->path); + if (imbuf) { + preview->icon_id = BKE_icon_imbuf_create(imbuf); + } + + done = true; + } - /* That way task freeing function won't free th preview, since it does not own it anymore. */ - atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL); - BLI_thread_queue_push(cache->previews_done, preview); + if (done) { + /* That way task freeing function won't free th preview, since it does not own it anymore. */ + atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL); + BLI_thread_queue_push(cache->previews_done, preview); + } // printf("%s: End (%d)...\n", __func__, threadid); } @@ -1314,8 +1541,8 @@ static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void /* preview_taskdata->preview is atomically set to NULL once preview has been processed and sent * to previews_done queue. */ if (preview != NULL) { - if (preview->img) { - IMB_freeImBuf(preview->img); + if (preview->icon_id) { + BKE_icon_delete(preview->icon_id); } MEM_freeN(preview); } @@ -1341,8 +1568,8 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache) while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) { // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, // preview->img); - if (preview->img) { - IMB_freeImBuf(preview->img); + if (preview->icon_id) { + BKE_icon_delete(preview->icon_id); } MEM_freeN(preview); } @@ -1373,10 +1600,11 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry BLI_assert(cache->flags & FLC_PREVIEWS_ACTIVE); - if (!entry->image && !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) && + if (!entry->preview_icon_id && !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) && (entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) { FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); + FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index]; if (entry->redirection_path) { BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR); @@ -1388,7 +1616,8 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry preview->index = index; preview->flags = entry->typeflag; - preview->img = NULL; + preview->in_memory_preview = intern_entry->local_data.preview_image; + preview->icon_id = 0; // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); filelist_cache_preview_ensure_running(cache); @@ -1496,25 +1725,45 @@ FileList *filelist_new(short type) p->selection_state = BLI_ghash_new( BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__); + p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET; + filelist_settype(p, type); - switch (type) { + return p; +} + +void filelist_settype(FileList *filelist, short type) +{ + if (filelist->type == type) { + return; + } + + filelist->type = type; + filelist->tags = 0; + switch (filelist->type) { case FILE_MAIN: - p->checkdirf = filelist_checkdir_main; - p->read_jobf = filelist_readjob_main; - p->filterf = is_filtered_main; + filelist->checkdirf = filelist_checkdir_main; + filelist->read_jobf = filelist_readjob_main; + filelist->filterf = is_filtered_main; break; case FILE_LOADLIB: - p->checkdirf = filelist_checkdir_lib; - p->read_jobf = filelist_readjob_lib; - p->filterf = is_filtered_lib; + filelist->checkdirf = filelist_checkdir_lib; + filelist->read_jobf = filelist_readjob_lib; + filelist->filterf = is_filtered_lib; + break; + case FILE_MAIN_ASSET: + filelist->checkdirf = filelist_checkdir_main_assets; + filelist->read_jobf = filelist_readjob_main_assets; + filelist->filterf = is_filtered_main_assets; + filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA | FILELIST_TAGS_NO_THREADS; break; default: - p->checkdirf = filelist_checkdir_dir; - p->read_jobf = filelist_readjob_dir; - p->filterf = is_filtered_file; + filelist->checkdirf = filelist_checkdir_dir; + filelist->read_jobf = filelist_readjob_dir; + filelist->filterf = is_filtered_file; break; } - return p; + + filelist->flags |= FL_FORCE_RESET; } void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection) @@ -1559,6 +1808,8 @@ void filelist_free(struct FileList *filelist) filelist->selection_state = NULL; } + MEM_SAFE_FREE(filelist->asset_library); + memset(&filelist->filter_data, 0, sizeof(filelist->filter_data)); filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING); @@ -1579,7 +1830,7 @@ BlendHandle *filelist_lib(struct FileList *filelist) static const char *fileentry_uiname(const char *root, const char *relpath, - const int typeflag, + const eFileSel_File_Types typeflag, char *buff) { char *name = NULL; @@ -1623,11 +1874,12 @@ bool filelist_is_dir(struct FileList *filelist, const char *path) */ void filelist_setdir(struct FileList *filelist, char *r_dir) { + const bool allow_invalid = filelist->asset_library != NULL; BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir); - const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true); - BLI_assert(is_valid_path); + const bool is_valid_path = filelist->checkdirf(filelist, r_dir, !allow_invalid); + BLI_assert(is_valid_path || allow_invalid); UNUSED_VARS_NDEBUG(is_valid_path); if (!STREQ(filelist->filelist.root, r_dir)) { @@ -1644,11 +1896,16 @@ void filelist_setrecursion(struct FileList *filelist, const int recursion_level) } } -bool filelist_force_reset(struct FileList *filelist) +bool filelist_needs_force_reset(FileList *filelist) { return (filelist->flags & FL_FORCE_RESET) != 0; } +void filelist_tag_force_reset(FileList *filelist) +{ + filelist->flags |= FL_FORCE_RESET; +} + bool filelist_is_ready(struct FileList *filelist) { return (filelist->flags & FL_IS_READY) != 0; @@ -1659,6 +1916,11 @@ bool filelist_pending(struct FileList *filelist) return (filelist->flags & FL_IS_PENDING) != 0; } +bool filelist_needs_reset_on_main_changes(const FileList *filelist) +{ + return (filelist->tags & FILELIST_TAGS_USES_MAIN_DATA) != 0; +} + /** * Limited version of full update done by space_file's file_refresh(), * to be used by operators and such. @@ -1667,7 +1929,7 @@ bool filelist_pending(struct FileList *filelist) */ int filelist_files_ensure(FileList *filelist) { - if (!filelist_force_reset(filelist) || !filelist_empty(filelist)) { + if (!filelist_needs_force_reset(filelist) || !filelist_needs_reading(filelist)) { filelist_sort(filelist); filelist_filter(filelist); } @@ -1700,6 +1962,17 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in if (entry->redirection_path) { ret->redirection_path = BLI_strdup(entry->redirection_path); } + ret->id = entry->local_data.id; + ret->asset_data = entry->imported_asset_data ? entry->imported_asset_data : NULL; + if (ret->id && (ret->asset_data == NULL)) { + ret->asset_data = ret->id->asset_data; + } + /* For some file types the preview is already available. */ + 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); + } BLI_addtail(&cache->cached_entries, ret); return ret; } @@ -1769,7 +2042,7 @@ int filelist_file_findpath(struct FileList *filelist, const char *filename) { int fidx = -1; - if (filelist->filelist.nbr_entries_filtered < 0) { + if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) { return fidx; } @@ -1787,9 +2060,17 @@ int filelist_file_findpath(struct FileList *filelist, const char *filename) return -1; } +/** + * Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET. + */ +ID *filelist_file_get_id(const FileDirEntry *file) +{ + return file->id; +} + FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]) { - if (filelist->filelist.nbr_entries_filtered < 0) { + if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) { return NULL; } @@ -2146,15 +2427,17 @@ bool filelist_cache_previews_update(FileList *filelist) // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - if (preview->img) { + if (preview->icon_id) { /* Due to asynchronous process, a preview for a given image may be generated several times, * i.e. entry->image may already be set at this point. */ - if (entry && !entry->image) { - entry->image = preview->img; + if (entry && !entry->preview_icon_id) { + /* Move ownership over icon. */ + entry->preview_icon_id = preview->icon_id; + preview->icon_id = 0; changed = true; } else { - IMB_freeImBuf(preview->img); + BKE_icon_delete(preview->icon_id); } } else if (entry) { @@ -2312,9 +2595,9 @@ int ED_file_extension_icon(const char *path) } } -int filelist_empty(struct FileList *filelist) +int filelist_needs_reading(struct FileList *filelist) { - return (filelist->filelist.nbr_entries == 0); + return (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET); } uint filelist_entry_select_set(const FileList *filelist, @@ -2563,8 +2846,8 @@ static int filelist_readjob_list_dir(const char *root, static int filelist_readjob_list_lib(const char *root, ListBase *entries, const bool skip_currpar) { FileListInternEntry *entry; - LinkNode *ln, *names; - int i, nnames, idcode = 0, nbr_entries = 0; + LinkNode *ln, *names = NULL, *datablock_infos = NULL; + int i, nitems, idcode = 0, nbr_entries = 0; char dir[FILE_MAX_LIBEXTRA], *group; bool ok; @@ -2586,11 +2869,11 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const * and freed in filelist_entry_free. */ if (group) { idcode = groupname_to_code(group); - names = BLO_blendhandle_get_datablock_names(libfiledata, idcode, &nnames); + datablock_infos = BLO_blendhandle_get_datablock_info(libfiledata, idcode, &nitems); } else { names = BLO_blendhandle_get_linkable_groups(libfiledata); - nnames = BLI_linklist_count(names); + nitems = BLI_linklist_count(names); } BLO_blendhandle_close(libfiledata); @@ -2603,12 +2886,18 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const nbr_entries++; } - for (i = 0, ln = names; i < nnames; i++, ln = ln->next) { - const char *blockname = ln->link; + for (i = 0, ln = (datablock_infos ? datablock_infos : names); i < nitems; i++, ln = ln->next) { + struct BLODataBlockInfo *info = datablock_infos ? ln->link : NULL; + const char *blockname = info ? info->name : ln->link; entry = MEM_callocN(sizeof(*entry), __func__); entry->relpath = BLI_strdup(blockname); entry->typeflag |= FILE_TYPE_BLENDERLIB; + if (info && info->asset_data) { + entry->typeflag |= FILE_TYPE_ASSET; + /* Moves ownership! */ + entry->imported_asset_data = info->asset_data; + } if (!(group && idcode)) { entry->typeflag |= FILE_TYPE_DIR; entry->blentype = groupname_to_code(blockname); @@ -2620,7 +2909,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const nbr_entries++; } - BLI_linklist_free(names, free); + BLI_linklist_freeN(datablock_infos ? datablock_infos : names); return nbr_entries; } @@ -2819,7 +3108,10 @@ static void filelist_readjob_do(const bool do_lib, // BLI_assert(filelist->filtered == NULL); BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && - (filelist->filelist.nbr_entries == 0)); + (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET)); + + /* A valid, but empty directory from now. */ + filelist->filelist.nbr_entries = 0; todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__); td_dir = BLI_stack_push_r(todo_dirs); @@ -2931,7 +3223,8 @@ static void filelist_readjob_do(const bool do_lib, BLI_stack_free(todo_dirs); } -static void filelist_readjob_dir(FileList *filelist, +static void filelist_readjob_dir(Main *UNUSED(current_main), + FileList *filelist, const char *main_name, short *stop, short *do_update, @@ -2941,7 +3234,8 @@ static void filelist_readjob_dir(FileList *filelist, filelist_readjob_do(false, filelist, main_name, stop, do_update, progress, lock); } -static void filelist_readjob_lib(FileList *filelist, +static void filelist_readjob_lib(Main *UNUSED(current_main), + FileList *filelist, const char *main_name, short *stop, short *do_update, @@ -2951,7 +3245,8 @@ static void filelist_readjob_lib(FileList *filelist, filelist_readjob_do(true, filelist, main_name, stop, do_update, progress, lock); } -static void filelist_readjob_main(FileList *filelist, +static void filelist_readjob_main(Main *current_main, + FileList *filelist, const char *main_name, short *stop, short *do_update, @@ -2959,12 +3254,67 @@ static void filelist_readjob_main(FileList *filelist, ThreadMutex *lock) { /* TODO! */ - filelist_readjob_dir(filelist, main_name, stop, do_update, progress, lock); + filelist_readjob_dir(current_main, filelist, main_name, stop, do_update, progress, lock); +} + +/** + * \warning Acts on main, so NOT thread-safe! + */ +static void filelist_readjob_main_assets(Main *current_main, + FileList *filelist, + const char *UNUSED(main_name), + short *UNUSED(stop), + short *do_update, + float *UNUSED(progress), + ThreadMutex *UNUSED(lock)) +{ + BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && + (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET)); + + /* A valid, but empty directory from now. */ + filelist->filelist.nbr_entries = 0; + + FileListInternEntry *entry; + ListBase tmp_entries = {0}; + ID *id_iter; + int nbr_entries = 0; + + FOREACH_MAIN_ID_BEGIN (current_main, id_iter) { + if (!id_iter->asset_data) { + continue; + } + + const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name)); + + entry = MEM_callocN(sizeof(*entry), __func__); + entry->relpath = BLI_strdup(id_code_name); + entry->name = BLI_strdup(id_iter->name + 2); + entry->typeflag |= FILE_TYPE_BLENDERLIB | FILE_TYPE_ASSET; + entry->blentype = GS(id_iter->name); + *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32( + (uint32_t *)filelist->filelist_intern.curr_uuid, 1); + entry->local_data.preview_image = BKE_asset_metadata_preview_get_from_id(id_iter->asset_data, + id_iter); + entry->local_data.id = id_iter; + nbr_entries++; + BLI_addtail(&tmp_entries, entry); + } + FOREACH_MAIN_ID_END; + + if (nbr_entries) { + *do_update = true; + + BLI_movelisttolist(&filelist->filelist.entries, &tmp_entries); + filelist->filelist.nbr_entries += nbr_entries; + filelist->filelist.nbr_entries_filtered = filelist->filelist.entry_idx_start = + filelist->filelist.entry_idx_end = -1; + } } typedef struct FileListReadJob { ThreadMutex lock; char main_name[FILE_MAX]; + Main *current_main; struct FileList *filelist; /** XXX We may use a simpler struct here... just a linked list and root path? */ struct FileList *tmp_filelist; @@ -2984,7 +3334,7 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update flrj->tmp_filelist = MEM_dupallocN(flrj->filelist); BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries); - flrj->tmp_filelist->filelist.nbr_entries = 0; + flrj->tmp_filelist->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET; flrj->tmp_filelist->filelist_intern.filtered = NULL; BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries); @@ -2995,11 +3345,17 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update flrj->tmp_filelist->libfiledata = NULL; memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache)); flrj->tmp_filelist->selection_state = NULL; + flrj->tmp_filelist->asset_library = NULL; BLI_mutex_unlock(&flrj->lock); - flrj->tmp_filelist->read_jobf( - flrj->tmp_filelist, flrj->main_name, stop, do_update, progress, &flrj->lock); + flrj->tmp_filelist->read_jobf(flrj->current_main, + flrj->tmp_filelist, + flrj->main_name, + stop, + do_update, + progress, + &flrj->lock); } static void filelist_readjob_update(void *flrjv) @@ -3014,7 +3370,7 @@ static void filelist_readjob_update(void *flrjv) BLI_mutex_lock(&flrj->lock); - if (flrj->tmp_filelist->filelist.nbr_entries) { + if (flrj->tmp_filelist->filelist.nbr_entries > 0) { /* We just move everything out of 'thread context' into final list. */ new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries; BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries); @@ -3032,7 +3388,7 @@ static void filelist_readjob_update(void *flrjv) /* if no new_nbr_entries, this is NOP */ BLI_movelisttolist(&fl_intern->entries, &new_entries); - flrj->filelist->filelist.nbr_entries = nbr_entries + new_nbr_entries; + flrj->filelist->filelist.nbr_entries = MAX2(nbr_entries, 0) + new_nbr_entries; } static void filelist_readjob_endjob(void *flrjv) @@ -3073,16 +3429,36 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) wmJob *wm_job; FileListReadJob *flrj; + if (!filelist_is_dir(filelist, filelist->filelist.root)) { + return; + } + /* prepare job data */ flrj = MEM_callocN(sizeof(*flrj), __func__); flrj->filelist = filelist; + flrj->current_main = bmain; BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name)); filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY); filelist->flags |= FL_IS_PENDING; + /* Init even for single threaded execution. Called functions use it. */ BLI_mutex_init(&flrj->lock); + if (filelist->tags & FILELIST_TAGS_NO_THREADS) { + short dummy_stop = false; + short dummy_do_update = false; + float dummy_progress = 0.0f; + + /* Single threaded execution. Just directly call the callbacks. */ + filelist_readjob_startjob(flrj, &dummy_stop, &dummy_do_update, &dummy_progress); + filelist_readjob_endjob(flrj); + filelist_readjob_free(flrj); + + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + return; + } + /* setup job */ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 4b8cc052382..16984bb6e43 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -29,6 +29,7 @@ extern "C" { struct BlendHandle; struct FileList; +struct FileSelectAssetLibraryUID; struct FileSelection; struct wmWindowManager; @@ -46,14 +47,16 @@ typedef enum FileCheckType { CHECK_ALL = 3, } FileCheckType; -struct ListBase *folderlist_new(void); void folderlist_free(struct ListBase *folderlist); -struct ListBase *folderlist_duplicate(ListBase *folderlist); void folderlist_popdir(struct ListBase *folderlist, char *dir); void folderlist_pushdir(struct ListBase *folderlist, const char *dir); const char *folderlist_peeklastdir(struct ListBase *folderlist); int folderlist_clear_next(struct SpaceFile *sfile); +void folder_history_list_ensure_for_active_browse_mode(struct SpaceFile *sfile); +void folder_history_list_free(struct SpaceFile *sfile); +struct ListBase folder_history_list_duplicate(struct ListBase *listbase); + void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort); void filelist_sort(struct FileList *filelist); @@ -63,17 +66,22 @@ void filelist_setfilter_options(struct FileList *filelist, const bool hide_parent, const uint64_t filter, const uint64_t filter_id, + const bool filter_assets_only, const char *filter_glob, const char *filter_search); void filelist_filter(struct FileList *filelist); +void filelist_setlibrary(struct FileList *filelist, + const struct FileSelectAssetLibraryUID *asset_library); void filelist_init_icons(void); void filelist_free_icons(void); struct ImBuf *filelist_getimage(struct FileList *filelist, const int index); +struct ImBuf *filelist_file_getimage(const FileDirEntry *file); struct ImBuf *filelist_geticon_image(struct FileList *filelist, const int index); int filelist_geticon(struct FileList *filelist, const int index, const bool is_main); struct FileList *filelist_new(short type); +void filelist_settype(struct FileList *filelist, short type); void filelist_clear(struct FileList *filelist); void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection); void filelist_free(struct FileList *filelist); @@ -83,15 +91,18 @@ bool filelist_is_dir(struct FileList *filelist, const char *path); void filelist_setdir(struct FileList *filelist, char *r_dir); int filelist_files_ensure(struct FileList *filelist); -int filelist_empty(struct FileList *filelist); +int filelist_needs_reading(struct FileList *filelist); FileDirEntry *filelist_file(struct FileList *filelist, int index); int filelist_file_findpath(struct FileList *filelist, const char *file); +struct ID *filelist_file_get_id(const struct FileDirEntry *file); FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]); void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size); bool filelist_file_cache_block(struct FileList *filelist, const int index); -bool filelist_force_reset(struct FileList *filelist); +bool filelist_needs_force_reset(struct FileList *filelist); +void filelist_tag_force_reset(struct FileList *filelist); bool filelist_pending(struct FileList *filelist); +bool filelist_needs_reset_on_main_changes(const struct FileList *filelist); bool filelist_is_ready(struct FileList *filelist); unsigned int filelist_entry_select_set(const struct FileList *filelist, diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 15c6972c5f5..b919a30e6cd 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -56,7 +56,9 @@ #include "BKE_appdir.h" #include "BKE_context.h" +#include "BKE_idtype.h" #include "BKE_main.h" +#include "BKE_preferences.h" #include "BLF_api.h" @@ -77,19 +79,76 @@ #define VERTLIST_MAJORCOLUMN_WIDTH (25 * UI_UNIT_X) -FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile) +static void fileselect_initialize_params_common(SpaceFile *sfile, FileSelectParams *params) { - if (!sfile->params) { - ED_fileselect_set_params(sfile); + const char *blendfile_path = BKE_main_blendfile_path_from_global(); + + /* operator has no setting for this */ + params->active_file = -1; + + if (!params->dir[0]) { + if (blendfile_path[0] != '\0') { + BLI_split_dir_part(blendfile_path, params->dir, sizeof(params->dir)); + } + else { + const char *doc_path = BKE_appdir_folder_default(); + if (doc_path) { + BLI_strncpy(params->dir, doc_path, sizeof(params->dir)); + } + } + } + + folder_history_list_ensure_for_active_browse_mode(sfile); + folderlist_pushdir(sfile->folders_prev, params->dir); + + /* Switching thumbnails needs to recalc layout T28809. */ + if (sfile->layout) { + sfile->layout->dirty = true; } - return sfile->params; +} + +static void fileselect_ensure_updated_asset_params(SpaceFile *sfile) +{ + BLI_assert(sfile->browse_mode == FILE_BROWSE_MODE_ASSETS); + BLI_assert(sfile->op == NULL); + + FileAssetSelectParams *asset_params = sfile->asset_params; + + if (!asset_params) { + asset_params = sfile->asset_params = MEM_callocN(sizeof(*asset_params), + "FileAssetSelectParams"); + asset_params->base_params.details_flags = U_default.file_space_data.details_flags; + asset_params->asset_library.type = FILE_ASSET_LIBRARY_LOCAL; + asset_params->asset_library.custom_library_index = -1; + } + + FileSelectParams *base_params = &asset_params->base_params; + base_params->file[0] = '\0'; + base_params->filter_glob[0] = '\0'; + /* TODO this way of using filters to form categories is notably slower than specifying a + * "group" to read. That's because all types are read and filtering is applied afterwards. Would + * be nice if we could lazy-read individual groups. */ + base_params->flag |= U_default.file_space_data.flag | FILE_ASSETS_ONLY | FILE_FILTER; + base_params->flag &= ~FILE_DIRSEL_ONLY; + base_params->filter |= FILE_TYPE_BLENDERLIB; + 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; + /* '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; + + fileselect_initialize_params_common(sfile, base_params); } /** * \note RNA_struct_property_is_set_ex is used here because we want * the previously used settings to be used here rather than overriding them */ -short ED_fileselect_set_params(SpaceFile *sfile) +static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile) { + BLI_assert(sfile->browse_mode == FILE_BROWSE_MODE_FILES); + FileSelectParams *params; wmOperator *op = sfile->op; @@ -136,20 +195,17 @@ short ED_fileselect_set_params(SpaceFile *sfile) RNA_string_get(op->ptr, "filepath", name); if (params->type == FILE_LOADLIB) { BLI_strncpy(params->dir, name, sizeof(params->dir)); - sfile->params->file[0] = '\0'; + params->file[0] = '\0'; } else { - BLI_split_dirfile(name, - sfile->params->dir, - sfile->params->file, - sizeof(sfile->params->dir), - sizeof(sfile->params->file)); + BLI_split_dirfile( + name, params->dir, params->file, sizeof(params->dir), sizeof(params->file)); } } else { if (is_directory && RNA_struct_property_is_set_ex(op->ptr, "directory", false)) { RNA_string_get(op->ptr, "directory", params->dir); - sfile->params->file[0] = '\0'; + params->file[0] = '\0'; } if (is_filename && RNA_struct_property_is_set_ex(op->ptr, "filename", false)) { @@ -298,34 +354,104 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->filter_glob[0] = '\0'; } - /* operator has no setting for this */ - params->active_file = -1; + fileselect_initialize_params_common(sfile, params); - /* initialize the list with previous folders */ - if (!sfile->folders_prev) { - sfile->folders_prev = folderlist_new(); - } + return params; +} - if (!sfile->params->dir[0]) { - if (blendfile_path[0] != '\0') { - BLI_split_dir_part(blendfile_path, sfile->params->dir, sizeof(sfile->params->dir)); - } - else { - const char *doc_path = BKE_appdir_folder_default(); - if (doc_path) { - BLI_strncpy(sfile->params->dir, doc_path, sizeof(sfile->params->dir)); +/** + * If needed, create and return the file select parameters for the active browse mode. + */ +FileSelectParams *ED_fileselect_ensure_active_params(SpaceFile *sfile) +{ + switch ((eFileBrowse_Mode)sfile->browse_mode) { + case FILE_BROWSE_MODE_FILES: + if (!sfile->params) { + fileselect_ensure_updated_file_params(sfile); + } + return sfile->params; + case FILE_BROWSE_MODE_ASSETS: + if (!sfile->asset_params) { + fileselect_ensure_updated_asset_params(sfile); } + return &sfile->asset_params->base_params; + } + + BLI_assert(!"Invalid browse mode set in file space."); + return NULL; +} + +/** + * Get the file select parameters for the active browse mode. + */ +FileSelectParams *ED_fileselect_get_active_params(const SpaceFile *sfile) +{ + if (!sfile) { + /* Sometimes called in poll before space type was checked. */ + return NULL; + } + + switch ((eFileBrowse_Mode)sfile->browse_mode) { + case FILE_BROWSE_MODE_FILES: + return sfile->params; + case FILE_BROWSE_MODE_ASSETS: + return (FileSelectParams *)sfile->asset_params; + } + + BLI_assert(!"Invalid browse mode set in file space."); + return NULL; +} + +FileSelectParams *ED_fileselect_get_file_params(const SpaceFile *sfile) +{ + return (sfile->browse_mode == FILE_BROWSE_MODE_FILES) ? sfile->params : NULL; +} + +FileAssetSelectParams *ED_fileselect_get_asset_params(const SpaceFile *sfile) +{ + return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) ? sfile->asset_params : NULL; +} + +static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params) +{ + FileSelectAssetLibraryUID *library = &asset_params->asset_library; + FileSelectParams *base_params = &asset_params->base_params; + bUserAssetLibrary *user_library = NULL; + + /* Ensure valid repo, or fall-back to local one. */ + if (library->type == FILE_ASSET_LIBRARY_CUSTOM) { + BLI_assert(library->custom_library_index >= 0); + + user_library = BKE_preferences_asset_library_find_from_index(&U, + library->custom_library_index); + if (!user_library) { + library->type = FILE_ASSET_LIBRARY_LOCAL; } } - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); + switch (library->type) { + case FILE_ASSET_LIBRARY_LOCAL: + base_params->dir[0] = '\0'; + break; + case FILE_ASSET_LIBRARY_CUSTOM: + BLI_assert(user_library); + BLI_strncpy(base_params->dir, user_library->path, sizeof(base_params->dir)); + break; + } + base_params->type = (library->type == FILE_ASSET_LIBRARY_LOCAL) ? FILE_MAIN_ASSET : FILE_LOADLIB; +} - /* Switching thumbnails needs to recalc layout T28809. */ - if (sfile->layout) { - sfile->layout->dirty = true; +void fileselect_refresh_params(SpaceFile *sfile) +{ + FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); + if (asset_params) { + fileselect_refresh_asset_params(asset_params); } +} - return 1; +bool ED_fileselect_is_asset_browser(const SpaceFile *sfile) +{ + return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS); } /* The subset of FileSelectParams.flag items we store into preferences. Note that FILE_SORT_ALPHA @@ -364,28 +490,28 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile) wmOperator *op = sfile->op; UserDef_FileSpaceData *sfile_udata = &U.file_space_data; - ED_fileselect_set_params(sfile); + sfile->browse_mode = FILE_BROWSE_MODE_FILES; + FileSelectParams *params = fileselect_ensure_updated_file_params(sfile); if (!op) { return; } - sfile->params->thumbnail_size = sfile_udata->thumbnail_size; - sfile->params->details_flags = sfile_udata->details_flags; - sfile->params->filter_id = sfile_udata->filter_id; + params->thumbnail_size = sfile_udata->thumbnail_size; + params->details_flags = sfile_udata->details_flags; + params->filter_id = sfile_udata->filter_id; /* Combine flags we take from params with the flags we take from userdef. */ - sfile->params->flag = (sfile->params->flag & ~PARAMS_FLAGS_REMEMBERED) | - (sfile_udata->flag & PARAMS_FLAGS_REMEMBERED); + params->flag = (params->flag & ~PARAMS_FLAGS_REMEMBERED) | + (sfile_udata->flag & PARAMS_FLAGS_REMEMBERED); if (file_select_use_default_display_type(sfile)) { - sfile->params->display = sfile_udata->display_type; + params->display = sfile_udata->display_type; } if (file_select_use_default_sort_type(sfile)) { - sfile->params->sort = sfile_udata->sort_type; + params->sort = sfile_udata->sort_type; /* For the default sorting, also take invert flag from userdef. */ - sfile->params->flag = (sfile->params->flag & ~FILE_SORT_INVERT) | - (sfile_udata->flag & FILE_SORT_INVERT); + params->flag = (params->flag & ~FILE_SORT_INVERT) | (sfile_udata->flag & FILE_SORT_INVERT); } } @@ -400,25 +526,26 @@ void ED_fileselect_params_to_userdef(SpaceFile *sfile, const int temp_win_size[2], const bool is_maximized) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data; UserDef_FileSpaceData sfile_udata_old = U.file_space_data; - sfile_udata_new->thumbnail_size = sfile->params->thumbnail_size; - sfile_udata_new->details_flags = sfile->params->details_flags; - sfile_udata_new->flag = sfile->params->flag & PARAMS_FLAGS_REMEMBERED; - sfile_udata_new->filter_id = sfile->params->filter_id; + sfile_udata_new->thumbnail_size = params->thumbnail_size; + sfile_udata_new->details_flags = params->details_flags; + sfile_udata_new->flag = params->flag & PARAMS_FLAGS_REMEMBERED; + sfile_udata_new->filter_id = params->filter_id; /* In some rare cases, operators ask for a specific display or sort type (e.g. chronological * sorting for "Recover Auto Save"). So the settings are optimized for a specific operation. * Don't let that change the userdef memory for more general cases. */ if (file_select_use_default_display_type(sfile)) { - sfile_udata_new->display_type = sfile->params->display; + sfile_udata_new->display_type = params->display; } if (file_select_use_default_sort_type(sfile)) { - sfile_udata_new->sort_type = sfile->params->sort; + sfile_udata_new->sort_type = params->sort; /* In this case also remember the invert flag. */ sfile_udata_new->flag = (sfile_udata_new->flag & ~FILE_SORT_INVERT) | - (sfile->params->flag & FILE_SORT_INVERT); + (params->flag & FILE_SORT_INVERT); } if (temp_win_size && !is_maximized) { @@ -432,14 +559,6 @@ void ED_fileselect_params_to_userdef(SpaceFile *sfile, } } -void ED_fileselect_reset_params(SpaceFile *sfile) -{ - sfile->params->type = FILE_UNIX; - sfile->params->flag = 0; - sfile->params->title[0] = '\0'; - sfile->params->active_file = -1; -} - /** * Sets FileSelectParams->file (name of selected file) */ @@ -447,7 +566,8 @@ void fileselect_file_set(SpaceFile *sfile, const int index) { const struct FileDirEntry *file = filelist_file(sfile->files, index); if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_DIR)) { - BLI_strncpy(sfile->params->file, file->relpath, FILE_MAXFILE); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + BLI_strncpy(params->file, file->relpath, FILE_MAXFILE); } } @@ -759,7 +879,7 @@ static void file_attribute_columns_init(const FileSelectParams *params, FileLayo void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region) { - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileLayout *layout = NULL; View2D *v2d = ®ion->v2d; int numfiles; @@ -873,7 +993,8 @@ void ED_file_change_dir_ex(bContext *C, bScreen *screen, ScrArea *area) return; } SpaceFile *sfile = area->spacedata.first; - if (sfile->params) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + if (params) { wmWindowManager *wm = CTX_wm_manager(C); Scene *scene = WM_windows_scene_get_from_screen(wm, screen); if (LIKELY(scene != NULL)) { @@ -882,20 +1003,20 @@ void ED_file_change_dir_ex(bContext *C, bScreen *screen, ScrArea *area) /* Clear search string, it is very rare to want to keep that filter while changing dir, * and usually very annoying to keep it actually! */ - sfile->params->filter_search[0] = '\0'; - sfile->params->active_file = -1; + params->filter_search[0] = '\0'; + params->active_file = -1; - if (!filelist_is_dir(sfile->files, sfile->params->dir)) { - BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir)); + if (!filelist_is_dir(sfile->files, params->dir)) { + BLI_strncpy(params->dir, filelist_dir(sfile->files), sizeof(params->dir)); /* could return but just refresh the current dir */ } - filelist_setdir(sfile->files, sfile->params->dir); + filelist_setdir(sfile->files, params->dir); if (folderlist_clear_next(sfile)) { folderlist_free(sfile->folders_next); } - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); + folderlist_pushdir(sfile->folders_prev, params->dir); file_draw_check_ex(C, area); } @@ -1010,7 +1131,8 @@ void ED_fileselect_clear(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfi filelist_clear(sfile->files); } - sfile->params->highlight_file = -1; + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + params->highlight_file = -1; WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -1036,8 +1158,7 @@ void ED_fileselect_exit(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfil sfile->op = NULL; } - folderlist_free(sfile->folders_prev); - folderlist_free(sfile->folders_next); + folder_history_list_free(sfile); if (sfile->files) { ED_fileselect_clear(wm, owner_scene, sfile); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 6ffe553e076..774dc54700c 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -35,6 +35,8 @@ #include "BKE_screen.h" #include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_message.h" @@ -55,6 +57,23 @@ #include "filelist.h" #include "fsmenu.h" +static ARegion *file_ui_region_ensure(ScrArea *area, ARegion *region_prev) +{ + ARegion *region; + + if ((region = BKE_area_find_region_type(area, RGN_TYPE_UI)) != NULL) { + return region; + } + + region = MEM_callocN(sizeof(ARegion), "execute region for file"); + BLI_insertlinkafter(&area->regionbase, region_prev, region); + region->regiontype = RGN_TYPE_UI; + region->alignment = RGN_ALIGN_TOP; + region->flag = RGN_FLAG_DYNAMIC_SIZE; + + return region; +} + static ARegion *file_execute_region_ensure(ScrArea *area, ARegion *region_prev) { ARegion *region; @@ -149,22 +168,10 @@ static void file_free(SpaceLink *sl) sfile->files = NULL; } - if (sfile->folders_prev) { - folderlist_free(sfile->folders_prev); - MEM_freeN(sfile->folders_prev); - sfile->folders_prev = NULL; - } + folder_history_list_free(sfile); - if (sfile->folders_next) { - folderlist_free(sfile->folders_next); - MEM_freeN(sfile->folders_next); - sfile->folders_next = NULL; - } - - if (sfile->params) { - MEM_freeN(sfile->params); - sfile->params = NULL; - } + MEM_SAFE_FREE(sfile->params); + MEM_SAFE_FREE(sfile->asset_params); if (sfile->layout) { MEM_freeN(sfile->layout); @@ -205,19 +212,20 @@ static SpaceLink *file_duplicate(SpaceLink *sl) sfilen->previews_timer = NULL; sfilen->smoothscroll_timer = NULL; + FileSelectParams *active_params_old = ED_fileselect_get_active_params(sfileo); + if (active_params_old) { + sfilen->files = filelist_new(active_params_old->type); + filelist_setdir(sfilen->files, active_params_old->dir); + } + if (sfileo->params) { - sfilen->files = filelist_new(sfileo->params->type); sfilen->params = MEM_dupallocN(sfileo->params); - filelist_setdir(sfilen->files, sfilen->params->dir); } - - if (sfileo->folders_prev) { - sfilen->folders_prev = folderlist_duplicate(sfileo->folders_prev); + if (sfileo->asset_params) { + sfilen->asset_params = MEM_dupallocN(sfileo->asset_params); } - if (sfileo->folders_next) { - sfilen->folders_next = folderlist_duplicate(sfileo->folders_next); - } + sfilen->folder_histories = folder_history_list_duplicate(&sfileo->folder_histories); if (sfileo->layout) { sfilen->layout = MEM_dupallocN(sfileo->layout); @@ -232,15 +240,30 @@ static void file_ensure_valid_region_state(bContext *C, SpaceFile *sfile, FileSelectParams *params) { - ARegion *region_ui = BKE_area_find_region_type(area, RGN_TYPE_UI); - ARegion *region_props = BKE_area_find_region_type(area, RGN_TYPE_TOOL_PROPS); - ARegion *region_execute = BKE_area_find_region_type(area, RGN_TYPE_EXECUTE); + ARegion *region_tools = BKE_area_find_region_type(area, RGN_TYPE_TOOLS); bool needs_init = false; /* To avoid multiple ED_area_init() calls. */ + BLI_assert(region_tools); + + if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) { + ARegion *region_execute = file_execute_region_ensure(area, region_tools); + ARegion *region_props = file_tool_props_region_ensure(area, region_execute); + + /* Hide specific regions by default. */ + region_props->flag |= RGN_FLAG_HIDDEN; + region_execute->flag |= RGN_FLAG_HIDDEN; + + ARegion *region_ui = BKE_area_find_region_type(area, RGN_TYPE_UI); + if (region_ui) { + ED_region_remove(C, area, region_ui); + needs_init = true; + } + } /* If there's an file-operation, ensure we have the option and execute region */ - if (sfile->op && (region_props == NULL)) { - region_execute = file_execute_region_ensure(area, region_ui); - region_props = file_tool_props_region_ensure(area, region_execute); + else if (sfile->op) { + ARegion *region_ui = file_ui_region_ensure(area, region_tools); + ARegion *region_execute = file_execute_region_ensure(area, region_ui); + ARegion *region_props = file_tool_props_region_ensure(area, region_execute); if (params->flag & FILE_HIDE_TOOL_PROPS) { region_props->flag |= RGN_FLAG_HIDDEN; @@ -252,12 +275,19 @@ static void file_ensure_valid_region_state(bContext *C, needs_init = true; } /* If there's _no_ file-operation, ensure we _don't_ have the option and execute region */ - else if ((sfile->op == NULL) && (region_props != NULL)) { - BLI_assert(region_execute != NULL); + else { + ARegion *region_props = BKE_area_find_region_type(area, RGN_TYPE_TOOL_PROPS); + ARegion *region_execute = BKE_area_find_region_type(area, RGN_TYPE_EXECUTE); + ARegion *region_ui = file_ui_region_ensure(area, region_tools); + UNUSED_VARS(region_ui); - ED_region_remove(C, area, region_props); - ED_region_remove(C, area, region_execute); - needs_init = true; + if (region_props) { + BLI_assert(region_execute); + + ED_region_remove(C, area, region_props); + ED_region_remove(C, area, region_execute); + needs_init = true; + } } if (needs_init) { @@ -265,24 +295,42 @@ static void file_ensure_valid_region_state(bContext *C, } } +/** + * Tag the space to recreate the file-list. + */ +static void file_tag_reset_list(ScrArea *area, SpaceFile *sfile) +{ + filelist_tag_force_reset(sfile->files); + ED_area_tag_refresh(area); +} + static void file_refresh(const bContext *C, ScrArea *area) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_ensure_active_params(sfile); + FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); struct FSMenu *fsmenu = ED_fsmenu_get(); - if (!sfile->folders_prev) { - sfile->folders_prev = folderlist_new(); + fileselect_refresh_params(sfile); + folder_history_list_ensure_for_active_browse_mode(sfile); + + if (sfile->files && (sfile->tags & FILE_TAG_REBUILD_MAIN_FILES) && + filelist_needs_reset_on_main_changes(sfile->files)) { + filelist_tag_force_reset(sfile->files); } + sfile->tags &= ~FILE_TAG_REBUILD_MAIN_FILES; + if (!sfile->files) { sfile->files = filelist_new(params->type); params->highlight_file = -1; /* added this so it opens nicer (ton) */ } + filelist_settype(sfile->files, params->type); filelist_setdir(sfile->files, params->dir); filelist_setrecursion(sfile->files, params->recursion_level); filelist_setsorting(sfile->files, params->sort, params->flag & FILE_SORT_INVERT); + filelist_setlibrary(sfile->files, asset_params ? &asset_params->asset_library : NULL); filelist_setfilter_options( sfile->files, (params->flag & FILE_FILTER) != 0, @@ -290,6 +338,7 @@ static void file_refresh(const bContext *C, ScrArea *area) true, /* Just always hide parent, prefer to not add an extra user option for this. */ params->filter, params->filter_id, + (params->flag & FILE_ASSETS_ONLY) != 0, params->filter_glob, params->filter_search); @@ -300,12 +349,12 @@ static void file_refresh(const bContext *C, ScrArea *area) sfile->bookmarknr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir); sfile->recentnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_RECENT, params->dir); - if (filelist_force_reset(sfile->files)) { + if (filelist_needs_force_reset(sfile->files)) { filelist_readjob_stop(wm, CTX_data_scene(C)); filelist_clear(sfile->files); } - if (filelist_empty(sfile->files)) { + if (filelist_needs_reading(sfile->files)) { if (!filelist_pending(sfile->files)) { filelist_readjob_start(sfile->files, C); } @@ -363,8 +412,21 @@ static void file_listener(wmWindow *UNUSED(win), ED_area_tag_refresh(area); } break; + case ND_SPACE_ASSET_PARAMS: + if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) { + ED_area_tag_refresh(area); + } + break; } break; + case NC_ASSET: { + if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { + /* Full refresh of the file list if local asset data was changed. Refreshing this view is + * cheap and users expect this to be updated immediately. */ + file_tag_reset_list(area, sfile); + } + break; + } } } @@ -413,7 +475,7 @@ static void file_main_region_message_subscribe(const struct bContext *UNUSED(C), struct wmMsgBus *mbus) { SpaceFile *sfile = area->spacedata.first; - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_ensure_active_params(sfile); /* This is a bit odd that a region owns the subscriber for an area, * keep for now since all subscribers for WM are regions. * May be worth re-visiting later. */ @@ -442,16 +504,31 @@ static void file_main_region_message_subscribe(const struct bContext *UNUSED(C), } } +static bool file_main_region_needs_refresh_before_draw(SpaceFile *sfile) +{ + /* Needed, because filelist is not initialized on loading */ + if (!sfile->files || filelist_needs_reading(sfile->files)) { + return true; + } + + /* File reading tagged the space because main data changed that may require a filelist reset. */ + if (filelist_needs_reset_on_main_changes(sfile->files) && + (sfile->tags & FILE_TAG_REBUILD_MAIN_FILES)) { + return true; + } + + return false; +} + static void file_main_region_draw(const bContext *C, ARegion *region) { /* draw entirely, view changes should be handled here */ SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_ensure_active_params(sfile); View2D *v2d = ®ion->v2d; - /* Needed, because filelist is not initialized on loading */ - if (!sfile->files || filelist_empty(sfile->files)) { + if (file_main_region_needs_refresh_before_draw(sfile)) { file_refresh(C, NULL); } @@ -497,7 +574,9 @@ static void file_main_region_draw(const bContext *C, ARegion *region) file_highlight_set(sfile, region, event->x, event->y); } - file_draw_list(C, region); + if (!file_draw_hint_if_invalid(sfile, region)) { + file_draw_list(C, region); + } /* reset view matrix */ UI_view2d_view_restore(C); @@ -681,6 +760,87 @@ static void file_dropboxes(void) WM_dropbox_add(lb, "FILE_OT_filepath_drop", filepath_drop_poll, filepath_drop_copy); } +static int file_space_subtype_get(ScrArea *area) +{ + SpaceFile *sfile = area->spacedata.first; + return sfile->browse_mode; +} + +static void file_space_subtype_set(ScrArea *area, int value) +{ + SpaceFile *sfile = area->spacedata.first; + sfile->browse_mode = value; +} + +static void file_space_subtype_item_extend(bContext *UNUSED(C), + EnumPropertyItem **item, + int *totitem) +{ + RNA_enum_items_add(item, totitem, rna_enum_space_file_browse_mode_items); +} + +static const char *file_context_dir[] = {"active_file", "active_id", NULL}; + +static int /*eContextResult*/ file_context(const bContext *C, + const char *member, + bContextDataResult *result) +{ + bScreen *screen = CTX_wm_screen(C); + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + + BLI_assert(!ED_area_is_global(CTX_wm_area(C))); + + if (CTX_data_dir(member)) { + CTX_data_dir_set(result, file_context_dir); + return CTX_RESULT_OK; + } + + /* The following member checks return file-list data, check if that needs refreshing first. */ + if (file_main_region_needs_refresh_before_draw(sfile)) { + return CTX_RESULT_NO_DATA; + } + + if (CTX_data_equals(member, "active_file")) { + FileDirEntry *file = filelist_file(sfile->files, params->active_file); + if (file == NULL) { + return CTX_RESULT_NO_DATA; + } + + CTX_data_pointer_set(result, &screen->id, &RNA_FileSelectEntry, file); + return CTX_RESULT_OK; + } + if (CTX_data_equals(member, "id")) { + const FileDirEntry *file = filelist_file(sfile->files, params->active_file); + if (file == NULL) { + return CTX_RESULT_NO_DATA; + } + + ID *id = filelist_file_get_id(file); + if (id == NULL) { + return CTX_RESULT_NO_DATA; + } + + CTX_data_id_pointer_set(result, id); + return CTX_RESULT_OK; + } + + return CTX_RESULT_MEMBER_NOT_FOUND; +} + +static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *UNUSED(new_id)) +{ + SpaceFile *sfile = (SpaceFile *)sl; + + /* If the file shows main data (IDs), tag it for reset. */ + if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { + /* Full refresh of the file list if main data was changed, don't even attempt remap pointers. + * We could give file list types a id-remap callback, but it's probably not worth it. + * Refreshing local file lists is relatively cheap. */ + file_tag_reset_list(area, sfile); + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_file(void) { @@ -700,6 +860,11 @@ void ED_spacetype_file(void) st->operatortypes = file_operatortypes; st->keymap = file_keymap; st->dropboxes = file_dropboxes; + st->space_subtype_item_extend = file_space_subtype_item_extend; + st->space_subtype_get = file_space_subtype_get; + st->space_subtype_set = file_space_subtype_set; + st->context = file_context; + st->id_remap = file_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt index 414e5c87f5a..2a795dd954c 100644 --- a/source/blender/editors/space_graph/CMakeLists.txt +++ b/source/blender/editors/space_graph/CMakeLists.txt @@ -34,8 +34,8 @@ set(SRC graph_draw.c graph_edit.c graph_ops.c - graph_slider_ops.c graph_select.c + graph_slider_ops.c graph_utils.c graph_view.c space_graph.c diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index ae34cd6cf6d..e56d71913d6 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -72,7 +72,9 @@ /* ************************************************************************** */ /* INSERT DUPLICATE AND BAKE KEYFRAMES */ -/* ******************** Insert Keyframes Operator ************************* */ +/* -------------------------------------------------------------------- */ +/** \name Insert Keyframes Operator + * \{ */ /* Mode defines for insert keyframes tool. */ typedef enum eGraphKeys_InsertKey_Types { @@ -290,7 +292,11 @@ void GRAPH_OT_keyframe_insert(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_insertkey_types, 0, "Type", ""); } -/* ******************** Click-Insert Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Click-Insert Keyframes Operator + * \{ */ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op) { @@ -444,8 +450,13 @@ void GRAPH_OT_click_insert(wmOperatorType *ot) "Extend selection instead of deselecting everything first"); } -/* ******************** Copy/Paste Keyframes Operator ************************* */ -/* NOTE: the backend code for this is shared with the dopesheet editor */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Copy/Paste Keyframes Operator + * + * \note the back-end code for this is shared with the dope-sheet editor. + * \{ */ static short copy_graph_keys(bAnimContext *ac) { @@ -605,7 +616,11 @@ void GRAPH_OT_paste(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************** Duplicate Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Duplicate Keyframes Operator + * \{ */ static void duplicate_graph_keys(bAnimContext *ac) { @@ -667,7 +682,11 @@ void GRAPH_OT_duplicate(wmOperatorType *ot) RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", ""); } -/* ******************** Delete Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Keyframes Operator + * \{ */ static bool delete_graph_keys(bAnimContext *ac) { @@ -746,7 +765,11 @@ void GRAPH_OT_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Clean Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clean Keyframes Operator + * \{ */ static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan) { @@ -816,8 +839,13 @@ void GRAPH_OT_clean(wmOperatorType *ot) RNA_def_boolean(ot->srna, "channels", false, "Channels", ""); } -/* ******************** Bake F-Curve Operator *********************** */ -/* This operator bakes the data of the selected F-Curves to F-Points */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Bake F-Curve Operator + * + * This operator bakes the data of the selected F-Curves to F-Points. + * \{ */ /* Bake each F-Curve into a set of samples. */ static void bake_graph_curves(bAnimContext *ac, int start, int end) @@ -899,8 +927,13 @@ void GRAPH_OT_bake(wmOperatorType *ot) /* TODO: add props for start/end frames (Joshua Leung 2009) */ } -/* ******************** Un-Bake F-Curve Operator *********************** */ -/* This operator unbakes the data of the selected F-Points to F-Curves. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Un-Bake F-Curve Operator + * + * This operator un-bakes the data of the selected F-Points to F-Curves. + * \{ */ /* Un-Bake F-Points into F-Curves. */ static void unbake_graph_curves(bAnimContext *ac, int start, int end) @@ -970,8 +1003,13 @@ void GRAPH_OT_unbake(wmOperatorType *ot) #ifdef WITH_AUDASPACE -/* ******************** Sound Bake F-Curve Operator *********************** */ -/* This operator bakes the given sound to the selected F-Curves */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sound Bake F-Curve Operator + * + * This operator bakes the given sound to the selected F-Curves. + * \{ */ /* ------------------- */ @@ -1204,10 +1242,14 @@ void GRAPH_OT_sound_bake(wmOperatorType *ot) 0.1); } -/* ******************** Sample Keyframes Operator *********************** */ -/* This operator 'bakes' the values of the curve into new keyframes between pairs +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sample Keyframes Operator + * + * This operator 'bakes' the values of the curve into new keyframes between pairs * of selected keyframes. It is useful for creating keyframes for tweaking overlap. - */ + * \{ */ /* Evaluates the curves between each selected keyframe on each frame, and keys the value. */ static void sample_graph_keys(bAnimContext *ac) @@ -1267,10 +1309,14 @@ void GRAPH_OT_sample(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + /* ************************************************************************** */ /* EXTRAPOLATION MODE AND KEYFRAME HANDLE SETTINGS */ -/* ******************** Set Extrapolation-Type Operator *********************** */ +/* -------------------------------------------------------------------- */ +/** \name Set Extrapolation-Type Operator + * \{ */ /* Defines for make/clear cyclic extrapolation tools. */ #define MAKE_CYCLIC_EXPO -1 @@ -1400,7 +1446,11 @@ void GRAPH_OT_extrapolation_type(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", ""); } -/* ******************** Set Interpolation-Type Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Interpolation-Type Operator + * \{ */ /* This function is responsible for setting interpolation mode for keyframes. */ static void setipo_graph_keys(bAnimContext *ac, short mode) @@ -1474,7 +1524,11 @@ void GRAPH_OT_interpolation_type(wmOperatorType *ot) ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", ""); } -/* ******************** Set Easing Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Easing Operator + * \{ */ static void seteasing_graph_keys(bAnimContext *ac, short mode) { @@ -1545,7 +1599,11 @@ void GRAPH_OT_easing_type(wmOperatorType *ot) ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", ""); } -/* ******************** Set Handle-Type Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Handle-Type Operator + * \{ */ /* This function is responsible for setting handle-type of selected keyframes. */ static void sethandles_graph_keys(bAnimContext *ac, short mode) @@ -1624,15 +1682,19 @@ void GRAPH_OT_handle_type(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", ""); } +/** \} */ + /* ************************************************************************** */ /* EULER FILTER */ -/* ***************** 'Euler Filter' Operator **************************** */ -/* Euler filter tools (as seen in Maya), are necessary for working with 'baked' +/* -------------------------------------------------------------------- */ +/** \name 'Euler Filter' Operator + * + * Euler filter tools (as seen in Maya), are necessary for working with 'baked' * rotation curves (with Euler rotations). The main purpose of such tools is to * resolve any discontinuities that may arise in the curves due to the clamping * of values to -180 degrees to 180 degrees. - */ + * \{ */ /* Set of three euler-rotation F-Curves. */ typedef struct tEulerFilter { @@ -1955,10 +2017,14 @@ void GRAPH_OT_euler_filter(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + /* ************************************************************************** */ /* SNAPPING */ -/* ***************** Jump to Selected Frames Operator *********************** */ +/* -------------------------------------------------------------------- */ +/** \name Jump to Selected Frames Operator + * \{ */ static bool graphkeys_framejump_poll(bContext *C) { @@ -2110,7 +2176,11 @@ void GRAPH_OT_snap_cursor_value(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Snap Keyframes Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Snap Keyframes Operator + * \{ */ /* Defines for snap keyframes tool. */ static const EnumPropertyItem prop_graphkeys_snap_types[] = { @@ -2262,7 +2332,11 @@ void GRAPH_OT_snap(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", ""); } -/* ******************** Mirror Keyframes Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mirror Keyframes Operator + * \{ */ /* Defines for mirror keyframes tool. */ static const EnumPropertyItem prop_graphkeys_mirror_types[] = { @@ -2280,12 +2354,12 @@ static const EnumPropertyItem prop_graphkeys_mirror_types[] = { {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", 0, - "By Times Over Time=0", + "By Times Over Zero Time", "Flip times of selected keyframes, effectively reversing the order they appear in"}, {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", 0, - "By Values Over Value=0", + "By Values Over Zero Value", "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"}, {GRAPHKEYS_MIRROR_MARKER, "MARKER", @@ -2421,7 +2495,11 @@ void GRAPH_OT_mirror(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", ""); } -/* ******************** Smooth Keyframes Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Smooth Keyframes Operator + * \{ */ static int graphkeys_smooth_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -2475,10 +2553,14 @@ void GRAPH_OT_smooth(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + /* ************************************************************************** */ /* F-CURVE MODIFIERS */ -/* ******************** Add F-Modifier Operator *********************** */ +/* -------------------------------------------------------------------- */ +/** \name Add F-Modifier Operator + * \{ */ static const EnumPropertyItem *graph_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(ptr), @@ -2596,7 +2678,11 @@ void GRAPH_OT_fmodifier_add(wmOperatorType *ot) ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve"); } -/* ******************** Copy F-Modifiers Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Copy F-Modifiers Operator + * \{ */ static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op) { @@ -2658,7 +2744,11 @@ void GRAPH_OT_fmodifier_copy(wmOperatorType *ot) #endif } -/* ******************** Paste F-Modifiers Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Paste F-Modifiers Operator + * \{ */ static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op) { @@ -2746,10 +2836,14 @@ void GRAPH_OT_fmodifier_paste(wmOperatorType *ot) "Replace existing F-Modifiers, instead of just appending to the end of the existing list"); } +/** \} */ + /* ************************************************************************** */ /* Drivers */ -/* ******************** Copy Driver Vars Operator *********************** */ +/* -------------------------------------------------------------------- */ +/** \name Copy Driver Variables Operator + * \{ */ static int graph_driver_vars_copy_exec(bContext *C, wmOperator *op) { @@ -2786,7 +2880,11 @@ void GRAPH_OT_driver_variables_copy(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Paste Driver Vars Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Paste Driver Variables Operator + * \{ */ static int graph_driver_vars_paste_exec(bContext *C, wmOperator *op) { @@ -2838,7 +2936,11 @@ void GRAPH_OT_driver_variables_paste(wmOperatorType *ot) "existing list"); } -/* ************************************************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Invalid Drivers Operator + * \{ */ static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op) { @@ -2926,3 +3028,5 @@ void GRAPH_OT_driver_delete_invalid(wmOperatorType *ot) /* Flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/** \} */ diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 12035ab6b61..4ab4ef518fb 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -1288,8 +1288,8 @@ void GRAPH_OT_select_less(wmOperatorType *ot) /* defines for left-right select tool */ static const EnumPropertyItem prop_graphkeys_leftright_select_types[] = { {GRAPHKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""}, - {GRAPHKEYS_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""}, - {GRAPHKEYS_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""}, + {GRAPHKEYS_LRSEL_LEFT, "LEFT", 0, "Before Current Frame", ""}, + {GRAPHKEYS_LRSEL_RIGHT, "RIGHT", 0, "After Current Frame", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c index 0b9ba3762a3..cde0dab3503 100644 --- a/source/blender/editors/space_graph/graph_view.c +++ b/source/blender/editors/space_graph/graph_view.c @@ -533,4 +533,4 @@ void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot) /* Flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -}
\ No newline at end of file +} diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index c0c0280959c..1996f05b36a 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -86,26 +86,9 @@ static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void * { uiBlock *block = uiLayoutGetBlock(layout); Image *image = image_p; - int slot_id; - uiDefBut(block, - UI_BTYPE_LABEL, - 0, - IFACE_("Slot"), - 0, - 0, - UI_UNIT_X * 5, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - uiItemS(layout); - - slot_id = BLI_listbase_count(&image->renderslots) - 1; - for (RenderSlot *slot = image->renderslots.last; slot; slot = slot->prev) { + int slot_id; + LISTBASE_FOREACH_INDEX (RenderSlot *, slot, &image->renderslots, slot_id) { char str[64]; if (slot->name[0] != '\0') { BLI_strncpy(str, slot->name, sizeof(str)); @@ -127,8 +110,23 @@ static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void * 0, -1, ""); - slot_id--; } + + uiItemS(layout); + uiDefBut(block, + UI_BTYPE_LABEL, + 0, + IFACE_("Slot"), + 0, + 0, + UI_UNIT_X * 5, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); } static bool ui_imageuser_slot_menu_step(bContext *C, int direction, void *image_p) @@ -175,14 +173,9 @@ static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void Image *image = rnd_data->image; ImageUser *iuser = rnd_data->iuser; Scene *scene = iuser->scene; - RenderResult *rr; - RenderLayer *rl; - RenderLayer rl_fake = {NULL}; - const char *fake_name; - int nr; - /* may have been freed since drawing */ - rr = BKE_image_acquire_renderresult(scene, image); + /* May have been freed since drawing. */ + RenderResult *rr = BKE_image_acquire_renderresult(scene, image); if (UNLIKELY(rr == NULL)) { return; } @@ -190,32 +183,26 @@ static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void UI_block_layout_set_current(block, layout); uiLayoutColumn(layout, false); - uiDefBut(block, - UI_BTYPE_LABEL, - 0, - IFACE_("Layer"), - 0, - 0, - UI_UNIT_X * 5, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - uiItemS(layout); - - nr = BLI_listbase_count(&rr->layers) - 1; - fake_name = ui_imageuser_layer_fake_name(rr); - + const char *fake_name = ui_imageuser_layer_fake_name(rr); if (fake_name) { - BLI_strncpy(rl_fake.name, fake_name, sizeof(rl_fake.name)); - nr += 1; + uiDefButS(block, + UI_BTYPE_BUT_MENU, + B_NOP, + fake_name, + 0, + 0, + UI_UNIT_X * 5, + UI_UNIT_X, + &iuser->layer, + 0.0, + 0.0, + 0, + -1, + ""); } - for (rl = rr->layers.last; rl; rl = rl->prev, nr--) { - final: + int nr = fake_name ? 1 : 0; + for (RenderLayer *rl = rr->layers.first; rl; rl = rl->next, nr++) { uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, @@ -232,13 +219,21 @@ static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void ""); } - if (fake_name) { - fake_name = NULL; - rl = &rl_fake; - goto final; - } - - BLI_assert(nr == -1); + uiItemS(layout); + uiDefBut(block, + UI_BTYPE_LABEL, + 0, + IFACE_("Layer"), + 0, + 0, + UI_UNIT_X * 5, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); BKE_image_release_renderresult(scene, image); } @@ -268,23 +263,6 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void * UI_block_layout_set_current(block, layout); uiLayoutColumn(layout, false); - uiDefBut(block, - UI_BTYPE_LABEL, - 0, - IFACE_("Pass"), - 0, - 0, - UI_UNIT_X * 5, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - - uiItemS(layout); - nr = (rl == NULL) ? 1 : 0; ListBase added_passes; @@ -315,6 +293,22 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void * ""); } + uiItemS(layout); + uiDefBut(block, + UI_BTYPE_LABEL, + 0, + IFACE_("Pass"), + 0, + 0, + UI_UNIT_X * 5, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); + BLI_freelistN(&added_passes); BKE_image_release_renderresult(scene, image); @@ -806,7 +800,8 @@ void uiTemplateImage(uiLayout *layout, C, ptr, propname, - ima ? NULL : "IMAGE_OT_new", + "IMAGE_OT_new", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index 180f1fb183c..c26f92c5463 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -407,6 +407,9 @@ bool ED_image_slot_cycle(struct Image *image, int direction) image->render_slot = ((cur == 1) ? 0 : 1); } + if ((cur != image->render_slot)) { + image->gpuflag |= IMA_GPU_REFRESH; + } return (cur != image->render_slot); } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 0fa48059cdc..a2c0819dc60 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -2649,7 +2649,7 @@ void IMAGE_OT_new(wmOperatorType *ot) "Generated Type", "Fill the image with a grid for UV map testing"); RNA_def_boolean( - ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); + ot->srna, "float", 0, "32-bit Float", "Create image with 32-bit floating-point bit depth"); RNA_def_property_flag(prop, PROP_HIDDEN); prop = RNA_def_boolean( ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views"); @@ -3737,7 +3737,7 @@ static void def_fill_tile(StructOrFunctionRNA *srna) /* Only needed when filling the first tile. */ RNA_def_boolean( - srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); + srna, "float", 0, "32-bit Float", "Create image with 32-bit floating-point bit depth"); RNA_def_boolean(srna, "alpha", 1, "Alpha", "Create an image with an alpha channel"); } diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c index 3ba088018c3..7dd8382c8ef 100644 --- a/source/blender/editors/space_info/info_report.c +++ b/source/blender/editors/space_info/info_report.c @@ -396,7 +396,7 @@ void INFO_OT_report_copy(wmOperatorType *ot) { /* identifiers */ ot->name = "Copy Reports to Clipboard"; - ot->description = "Copy selected reports to Clipboard"; + ot->description = "Copy selected reports to clipboard"; ot->idname = "INFO_OT_report_copy"; /* api callbacks */ diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 083fd641dc1..218fc3b7141 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -292,8 +292,9 @@ static void nla_panel_animdata(const bContext *C, Panel *panel) (bContext *)C, &adt_ptr, "action", - "ACTION_OT_new", NULL, + "ACTION_OT_new", + "ACTION_OT_duplicate_assign", "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL, false, @@ -345,7 +346,7 @@ static void nla_panel_stripname(const bContext *C, Panel *panel) uiItemR(row, &strip_ptr, "name", 0, "", ICON_NLA); - UI_block_emboss_set(block, UI_EMBOSS_NONE); + UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); uiItemR(row, &strip_ptr, "mute", 0, "", ICON_NONE); UI_block_emboss_set(block, UI_EMBOSS); } diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 561de5e82a6..9832ca975cf 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -292,7 +292,7 @@ static int mouse_nla_channels( /* TODO: make this use the operator instead of calling the function directly * however, calling the operator requires that we supply the args, * and that works with proper buttons only */ - BKE_nla_action_pushdown(adt); + BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(ale->id)); } else { /* when in tweakmode, this button becomes the toggle for mapped editing */ @@ -516,7 +516,7 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op) } /* 'push-down' action - only usable when not in TweakMode */ - BKE_nla_action_pushdown(adt); + BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(id)); struct Main *bmain = CTX_data_main(C); DEG_id_tag_update_ex(bmain, id, ID_RECALC_ANIMATION); @@ -648,19 +648,21 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel) NlaTrack *nlt = (NlaTrack *)ale->data; AnimData *adt = ale->adt; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); + /* check if just adding a new track above this one, * or whether we're adding a new one to the top of the stack that this one belongs to */ if (above_sel) { /* just add a new one above this one */ - BKE_nlatrack_add(adt, nlt); + BKE_nlatrack_add(adt, nlt, is_liboverride); ale->update = ANIM_UPDATE_DEPS; added = true; } else if ((lastAdt == NULL) || (adt != lastAdt)) { /* add one track to the top of the owning AnimData's stack, * then don't add anymore to this stack */ - BKE_nlatrack_add(adt, NULL); + BKE_nlatrack_add(adt, NULL, is_liboverride); lastAdt = adt; ale->update = ANIM_UPDATE_DEPS; added = true; @@ -698,7 +700,7 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac) /* ensure it is empty */ if (BLI_listbase_is_empty(&adt->nla_tracks)) { /* add new track to this AnimData block then */ - BKE_nlatrack_add(adt, NULL); + BKE_nlatrack_add(adt, NULL, ID_IS_OVERRIDE_LIBRARY(ale->id)); ale->update = ANIM_UPDATE_DEPS; added = true; } @@ -796,6 +798,11 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op)) NlaTrack *nlt = (NlaTrack *)ale->data; AnimData *adt = ale->adt; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No deletion of non-local tracks of override data. */ + continue; + } + /* if track is currently 'solo', then AnimData should have its * 'has solo' flag disabled */ diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index ed8e5ad76e9..3fa1b614a03 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -649,6 +649,7 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op) NlaTrack *nlt = (NlaTrack *)ale->data; AnimData *adt = ale->adt; NlaStrip *strip = NULL; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); /* Sanity check: only apply actions of the right type for this ID. * NOTE: in the case that this hasn't been set, @@ -671,12 +672,12 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op) strip->start = cfra; /* firstly try adding strip to our current track, but if that fails, add to a new track */ - if (BKE_nlatrack_add_strip(nlt, strip) == 0) { + if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) { /* trying to add to the current failed (no space), * so add a new track to the stack, and add to that... */ - nlt = BKE_nlatrack_add(adt, NULL); - BKE_nlatrack_add_strip(nlt, strip); + nlt = BKE_nlatrack_add(adt, NULL, is_liboverride); + BKE_nlatrack_add_strip(nlt, strip, is_liboverride); } /* auto-name it */ @@ -886,6 +887,7 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op)) AnimData *adt = ale->adt; NlaTrack *nlt = (NlaTrack *)ale->data; NlaStrip *strip; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); /* does this belong to speaker - assumed to live on Object level only */ if ((GS(ale->id->name) != ID_OB) || (ob->type != OB_SPEAKER)) { @@ -899,12 +901,12 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op)) strip->end += cfra; /* firstly try adding strip to our current track, but if that fails, add to a new track */ - if (BKE_nlatrack_add_strip(nlt, strip) == 0) { + if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) { /* trying to add to the current failed (no space), * so add a new track to the stack, and add to that... */ - nlt = BKE_nlatrack_add(adt, NULL); - BKE_nlatrack_add_strip(nlt, strip); + nlt = BKE_nlatrack_add(adt, NULL, is_liboverride); + BKE_nlatrack_add_strip(nlt, strip, is_liboverride); } /* auto-name it */ @@ -966,6 +968,11 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op)) AnimData *adt = ale->adt; NlaStrip *strip; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No making metastrips in non-local tracks of override data. */ + continue; + } + /* create meta-strips from the continuous chains of selected strips */ BKE_nlastrips_make_metas(&nlt->strips, 0); @@ -1030,6 +1037,11 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op)) for (ale = anim_data.first; ale; ale = ale->next) { NlaTrack *nlt = (NlaTrack *)ale->data; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No removing metastrips from non-local tracks of override data. */ + continue; + } + /* clear all selected meta-strips, regardless of whether they are temporary or not */ BKE_nlastrips_clear_metas(&nlt->strips, 1, 0); @@ -1096,6 +1108,11 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op) NlaStrip *strip, *nstrip, *next; NlaTrack *track; + /* Note: We allow this operator in override context because it is almost always (from possible + * default user interactions) paired with the transform one, which will ensure that the new + * strip ends up in a valid (local) track. */ + + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); for (strip = nlt->strips.first; strip; strip = next) { next = strip->next; @@ -1106,13 +1123,13 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op) /* in case there's no space in the track above, * or we haven't got a reference to it yet, try adding */ - if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) { + if (BKE_nlatrack_add_strip(nlt->next, nstrip, is_liboverride) == 0) { /* need to add a new track above the one above the current one * - if the current one is the last one, nlt->next will be NULL, which defaults to adding * at the top of the stack anyway... */ - track = BKE_nlatrack_add(adt, nlt->next); - BKE_nlatrack_add_strip(track, nstrip); + track = BKE_nlatrack_add(adt, nlt->next, is_liboverride); + BKE_nlatrack_add_strip(track, nstrip, is_liboverride); } /* deselect the original and the active flag */ @@ -1209,6 +1226,11 @@ static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op)) NlaTrack *nlt = (NlaTrack *)ale->data; NlaStrip *strip, *nstrip; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No deletion of strips in non-local tracks of override data. */ + continue; + } + for (strip = nlt->strips.first; strip; strip = nstrip) { nstrip = strip->next; @@ -1359,6 +1381,11 @@ static int nlaedit_split_exec(bContext *C, wmOperator *UNUSED(op)) AnimData *adt = ale->adt; NlaStrip *strip, *next; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No splitting of strips in non-local tracks of override data. */ + continue; + } + for (strip = nlt->strips.first; strip; strip = next) { next = strip->next; @@ -1502,6 +1529,12 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op) NlaStrip *strip, *stripN = NULL; NlaStrip *area = NULL, *sb = NULL; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); + + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No re-ordering of strips whithin non-local tracks of override data. */ + continue; + } /* make temporary metastrips so that entire islands of selections can be moved around */ BKE_nlastrips_make_metas(&nlt->strips, 1); @@ -1610,8 +1643,8 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op) } /* add strips back to track now */ - BKE_nlatrack_add_strip(nlt, area); - BKE_nlatrack_add_strip(nlt, sb); + BKE_nlatrack_add_strip(nlt, area, is_liboverride); + BKE_nlatrack_add_strip(nlt, sb, is_liboverride); } /* clear (temp) metastrips */ @@ -1674,11 +1707,19 @@ static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op)) NlaTrack *nltn = nlt->next; NlaStrip *strip, *stripn; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); + /* if this track has no tracks after it, skip for now... */ if (nltn == NULL) { continue; } + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt) || + BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nltn)) { + /* No moving of strips in non-local tracks of override data. */ + continue; + } + /* for every selected strip, try to move */ for (strip = nlt->strips.first; strip; strip = stripn) { stripn = strip->next; @@ -1689,7 +1730,7 @@ static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op)) /* remove from its current track, and add to the one above * (it 'should' work, so no need to worry) */ BLI_remlink(&nlt->strips, strip); - BKE_nlatrack_add_strip(nltn, strip); + BKE_nlatrack_add_strip(nltn, strip, is_liboverride); } } } @@ -1751,11 +1792,19 @@ static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op)) NlaTrack *nltp = nlt->prev; NlaStrip *strip, *stripn; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); + /* if this track has no tracks before it, skip for now... */ if (nltp == NULL) { continue; } + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt) || + BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nltp)) { + /* No moving of strips in non-local tracks of override data. */ + continue; + } + /* for every selected strip, try to move */ for (strip = nlt->strips.first; strip; strip = stripn) { stripn = strip->next; @@ -1766,7 +1815,7 @@ static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op)) /* remove from its current track, and add to the one above * (it 'should' work, so no need to worry) */ BLI_remlink(&nlt->strips, strip); - BKE_nlatrack_add_strip(nltp, strip); + BKE_nlatrack_add_strip(nltp, strip, is_liboverride); } } } @@ -2023,11 +2072,11 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op)) /* strip must be selected, and must be action-clip only * (transitions don't have scale) */ if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) { - /* if the referenced action is used by other strips, - * make this strip use its own copy */ - if (strip->act == NULL) { + if (strip->act == NULL || ID_IS_OVERRIDE_LIBRARY(strip->act) || ID_IS_LINKED(strip->act)) { continue; } + /* if the referenced action is used by other strips, + * make this strip use its own copy */ if (strip->act->id.us > 1) { /* make a copy of the Action to work on */ bAction *act = (bAction *)BKE_id_copy(bmain, &strip->act->id); @@ -2200,6 +2249,8 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op) NlaStrip *strip, *stripn; NlaTrack *track; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); + /* create meta-strips from the continuous chains of selected strips */ BKE_nlastrips_make_metas(&nlt->strips, 1); @@ -2255,10 +2306,10 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op) BLI_remlink(&tmp_strips, strip); /* in case there's no space in the current track, try adding */ - if (BKE_nlatrack_add_strip(nlt, strip) == 0) { + if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) { /* need to add a new track above the current one */ - track = BKE_nlatrack_add(adt, nlt); - BKE_nlatrack_add_strip(track, strip); + track = BKE_nlatrack_add(adt, nlt, is_liboverride); + BKE_nlatrack_add_strip(track, strip, is_liboverride); /* clear temp meta-strips on this new track, * as we may not be able to get back to it */ @@ -2375,6 +2426,11 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op) NlaTrack *nlt = (NlaTrack *)ale->data; NlaStrip *strip; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No adding f-modifiers to strips in non-local tracks of override data. */ + continue; + } + for (strip = nlt->strips.first; strip; strip = strip->next) { /* can F-Modifier be added to the current strip? */ if (active_only) { @@ -2552,6 +2608,11 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op) NlaTrack *nlt = (NlaTrack *)ale->data; NlaStrip *strip; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No pasting in non-local tracks of override data. */ + continue; + } + for (strip = nlt->strips.first; strip; strip = strip->next) { /* can F-Modifier be added to the current strip? */ if (active_only) { diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index d8f31161c20..f4a3bb96aeb 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -21,6 +21,7 @@ set(INC ../../blenkernel ../../blenlib ../../blentranslation + ../../compositor ../../depsgraph ../../draw ../../gpu @@ -29,7 +30,6 @@ set(INC ../../makesrna ../../nodes ../../render - ../../compositor ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 84e7a74fab3..0ce31707204 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -203,42 +203,6 @@ static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA * uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE); } -#if 0 /* not used in 2.5x yet */ -static void node_browse_tex_cb(bContext *C, void *ntree_v, void *node_v) -{ - Main *bmain = CTX_data_main(C); - bNodeTree *ntree = ntree_v; - bNode *node = node_v; - Tex *tex; - - if (node->menunr < 1) { - return; - } - - if (node->id) { - id_us_min(node->id); - node->id = NULL; - } - tex = BLI_findlink(&bmain->tex, node->menunr - 1); - - node->id = &tex->id; - id_us_plus(node->id); - BLI_strncpy(node->name, node->id->name + 2, sizeof(node->name)); - - nodeSetActive(ntree, node); - - if (ntree->type == NTREE_TEXTURE) { - ntreeTexCheckCyclics(ntree); - } - - // allqueue(REDRAWBUTSSHADING, 0); - // allqueue(REDRAWNODE, 0); - NodeTagChanged(ntree, node); - - node->menunr = 0; -} -#endif - static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = ptr->data; @@ -771,6 +735,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA ptr, "image", "IMAGE_OT_new", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, @@ -808,6 +773,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin ptr, "image", "IMAGE_OT_new", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, @@ -1395,6 +1361,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA * ptr, "image", "IMAGE_OT_new", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, @@ -1426,7 +1393,8 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer bNode *node = ptr->data; uiLayout *col, *row; - uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID( + layout, C, ptr, "scene", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); if (!node->id) { return; @@ -1548,7 +1516,8 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, NULL, ICON_NONE); - uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID( + layout, C, ptr, "scene", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, NULL, ICON_NONE); @@ -2163,8 +2132,17 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); } static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -2172,8 +2150,17 @@ static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, Point bNode *node = ptr->data; PointerRNA clipptr; - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); if (!node->id) { return; @@ -2188,8 +2175,17 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe { bNode *node = ptr->data; - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); if (!node->id) { return; @@ -2214,8 +2210,17 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po { bNode *node = ptr->data; - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); if (!node->id) { return; @@ -2538,7 +2543,8 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID( + layout, C, ptr, "mask", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, NULL, ICON_NONE); uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE); @@ -2559,7 +2565,8 @@ static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, Point { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID( + layout, C, ptr, "clip", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); if (node->id) { MovieClip *clip = (MovieClip *)node->id; @@ -2595,8 +2602,17 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN { bNode *node = ptr->data; - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); if (node->id) { MovieClip *clip = (MovieClip *)node->id; @@ -2636,8 +2652,17 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P bNode *node = ptr->data; NodePlaneTrackDeformData *data = node->storage; - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); if (node->id) { MovieClip *clip = (MovieClip *)node->id; @@ -3072,6 +3097,7 @@ static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *p ptr, "image", "IMAGE_OT_new", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, @@ -3149,6 +3175,15 @@ static void node_geometry_buts_boolean_math(uiLayout *layout, bContext *UNUSED(C uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); } +static void node_geometry_buts_attribute_compare(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "input_type_a", DEFAULT_FLAGS, IFACE_("Type A"), ICON_NONE); + uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE); +} + static void node_geometry_buts_subdivision_surface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr)) @@ -3182,6 +3217,49 @@ static void node_geometry_buts_attribute_math(uiLayout *layout, uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE); } +static void node_geometry_buts_point_instance(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "instance_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + if (RNA_enum_get(ptr, "instance_type") == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION) { + uiItemR(layout, ptr, "use_whole_collection", DEFAULT_FLAGS, NULL, ICON_NONE); + } +} + +static void node_geometry_buts_attribute_fill(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); + // uiItemR(layout, ptr, "domain", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_geometry_buts_attribute_mix(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE); + uiLayout *col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "input_type_factor", DEFAULT_FLAGS, IFACE_("Factor"), ICON_NONE); + uiItemR(col, ptr, "input_type_a", DEFAULT_FLAGS, IFACE_("A"), ICON_NONE); + uiItemR(col, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("B"), ICON_NONE); +} + +static void node_geometry_buts_attribute_point_distribute(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "distribute_method", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_geometry_buts_attribute_color_ramp(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiTemplateColorRamp(layout, ptr, "color_ramp", 0); +} + static void node_geometry_set_butfunc(bNodeType *ntype) { switch (ntype->type) { @@ -3194,12 +3272,30 @@ static void node_geometry_set_butfunc(bNodeType *ntype) case GEO_NODE_TRIANGULATE: ntype->draw_buttons = node_geometry_buts_triangulate; break; - case GEO_NODE_RANDOM_ATTRIBUTE: + case GEO_NODE_ATTRIBUTE_RANDOMIZE: ntype->draw_buttons = node_geometry_buts_random_attribute; break; case GEO_NODE_ATTRIBUTE_MATH: ntype->draw_buttons = node_geometry_buts_attribute_math; break; + case GEO_NODE_ATTRIBUTE_COMPARE: + ntype->draw_buttons = node_geometry_buts_attribute_compare; + break; + case GEO_NODE_POINT_INSTANCE: + ntype->draw_buttons = node_geometry_buts_point_instance; + break; + case GEO_NODE_ATTRIBUTE_FILL: + ntype->draw_buttons = node_geometry_buts_attribute_fill; + break; + case GEO_NODE_ATTRIBUTE_MIX: + ntype->draw_buttons = node_geometry_buts_attribute_mix; + break; + case GEO_NODE_POINT_DISTRIBUTE: + ntype->draw_buttons = node_geometry_buts_attribute_point_distribute; + break; + case GEO_NODE_ATTRIBUTE_COLOR_RAMP: + ntype->draw_buttons = node_geometry_buts_attribute_color_ramp; + break; } } @@ -3222,6 +3318,12 @@ static void node_function_buts_switch(uiLayout *layout, bContext *UNUSED(C), Poi uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); } +static void node_function_buts_input_vector(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "vector", UI_ITEM_R_EXPAND, "", ICON_NONE); +} + static void node_function_set_butfunc(bNodeType *ntype) { switch (ntype->type) { @@ -3234,6 +3336,9 @@ static void node_function_set_butfunc(bNodeType *ntype) case FN_NODE_SWITCH: ntype->draw_buttons = node_function_buts_switch; break; + case FN_NODE_INPUT_VECTOR: + ntype->draw_buttons = node_function_buts_input_vector; + break; } } @@ -3389,6 +3494,7 @@ static const float std_node_socket_colors[][4] = { {0.93, 0.62, 0.36, 1.0}, /* SOCK_OBJECT */ {0.89, 0.76, 0.43, 1.0}, /* SOCK_IMAGE */ {0.00, 0.84, 0.64, 1.0}, /* SOCK_GEOMETRY */ + {0.96, 0.96, 0.96, 1.0}, /* SOCK_COLLECTION */ }; /* common color callbacks for standard types */ @@ -3512,6 +3618,10 @@ static void std_node_socket_draw( uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); break; } + case SOCK_COLLECTION: { + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); + break; + } default: node_socket_button_label(C, layout, ptr, node_ptr, text); break; diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index fc7fa3a6caa..d3fec7257f5 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -344,8 +344,6 @@ void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry) /* based on settings in node, sets drawing rect info. each redraw! */ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) { - uiLayout *layout, *row; - PointerRNA nodeptr; RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); @@ -374,15 +372,15 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) PointerRNA sockptr; RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr); - layout = UI_block_layout(node->block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - locx + NODE_DYS, - dy, - NODE_WIDTH(node) - NODE_DY, - NODE_DY, - 0, - UI_style_get_dpi()); + uiLayout *layout = UI_block_layout(node->block, + UI_LAYOUT_VERTICAL, + UI_LAYOUT_PANEL, + locx + NODE_DYS, + dy, + NODE_WIDTH(node) - NODE_DY, + NODE_DY, + 0, + UI_style_get_dpi()); if (node->flag & NODE_MUTED) { uiLayoutSetActive(layout, false); @@ -393,7 +391,7 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) uiLayoutSetContextPointer(layout, "socket", &sockptr); /* align output buttons to the right */ - row = uiLayoutRow(layout, 1); + uiLayout *row = uiLayoutRow(layout, true); uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT); const char *socket_label = nodeSocketLabel(nsock); nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label)); @@ -469,15 +467,15 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) node->butr.ymin = 0; node->butr.ymax = 0; - layout = UI_block_layout(node->block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - locx + NODE_DYS, - dy, - node->butr.xmax, - 0, - 0, - UI_style_get_dpi()); + uiLayout *layout = UI_block_layout(node->block, + UI_LAYOUT_VERTICAL, + UI_LAYOUT_PANEL, + locx + NODE_DYS, + dy, + node->butr.xmax, + 0, + 0, + UI_style_get_dpi()); if (node->flag & NODE_MUTED) { uiLayoutSetActive(layout, false); @@ -502,15 +500,15 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) PointerRNA sockptr; RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr); - layout = UI_block_layout(node->block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - locx + NODE_DYS, - dy, - NODE_WIDTH(node) - NODE_DY, - NODE_DY, - 0, - UI_style_get_dpi()); + uiLayout *layout = UI_block_layout(node->block, + UI_LAYOUT_VERTICAL, + UI_LAYOUT_PANEL, + locx + NODE_DYS, + dy, + NODE_WIDTH(node) - NODE_DY, + NODE_DY, + 0, + UI_style_get_dpi()); if (node->flag & NODE_MUTED) { uiLayoutSetActive(layout, false); @@ -520,7 +518,7 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) uiLayoutSetContextPointer(layout, "node", &nodeptr); uiLayoutSetContextPointer(layout, "socket", &sockptr); - row = uiLayoutRow(layout, 1); + uiLayout *row = uiLayoutRow(layout, true); const char *socket_label = nodeSocketLabel(nsock); nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label)); @@ -771,7 +769,6 @@ void node_socket_color_get( bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4]) { PointerRNA ptr; - BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node)); RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); @@ -1623,7 +1620,6 @@ void node_draw_nodetree(const bContext *C, } bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); - node->nr = a; /* index of node in list, used for exec event code */ node_draw(C, region, snode, ntree, node, key); } @@ -1646,7 +1642,6 @@ void node_draw_nodetree(const bContext *C, } bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); - node->nr = a; /* index of node in list, used for exec event code */ node_draw(C, region, snode, ntree, node, key); } } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 039ddad71ef..e6f11f3eb83 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -100,9 +100,7 @@ typedef struct CompoJob { static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags) { - bNode *node; - - for (node = nodetree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &nodetree->nodes) { if (node->type == CMP_NODE_COMPOSITE) { if (recalc_flags & COM_RECALC_COMPOSITE) { node->flag |= NODE_DO_OUTPUT_RECALC; @@ -124,14 +122,12 @@ static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags) static int compo_get_recalc_flags(const bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); - wmWindow *win; int recalc_flags = 0; - for (win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { const bScreen *screen = WM_window_get_active_screen(win); - ScrArea *area; - for (area = screen->areabase.first; area; area = area->next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area->spacetype == SPACE_IMAGE) { SpaceImage *sima = area->spacedata.first; if (sima->image) { @@ -247,7 +243,6 @@ static void compo_startjob(void *cjv, CompoJob *cj = cjv; bNodeTree *ntree = cj->localtree; Scene *scene = cj->scene; - SceneRenderView *srv; if (scene->use_nodes == false) { return; @@ -280,7 +275,7 @@ static void compo_startjob(void *cjv, ""); } else { - for (srv = scene->r.views.first; srv; srv = srv->next) { + LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) { if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) { continue; } @@ -309,8 +304,6 @@ static void compo_startjob(void *cjv, */ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner) { - wmJob *wm_job; - CompoJob *cj; Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -327,13 +320,13 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene BKE_image_backup_render( scene, BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result"), false); - wm_job = WM_jobs_get(CTX_wm_manager(C), - CTX_wm_window(C), - scene_owner, - "Compositing", - WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS, - WM_JOB_TYPE_COMPOSITE); - cj = MEM_callocN(sizeof(CompoJob), "compo job"); + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + scene_owner, + "Compositing", + WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS, + WM_JOB_TYPE_COMPOSITE); + CompoJob *cj = MEM_callocN(sizeof(CompoJob), "compo job"); /* customdata for preview thread */ cj->bmain = bmain; @@ -524,9 +517,6 @@ void ED_node_shader_default(const bContext *C, ID *id) /* called from shading buttons or header */ void ED_node_composit_default(const bContext *C, struct Scene *sce) { - bNode *in, *out; - bNodeSocket *fromsock, *tosock; - /* but lets check it anyway */ if (sce->nodetree) { if (G.debug & G_DEBUG) { @@ -541,18 +531,18 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce) sce->nodetree->edit_quality = NTREE_QUALITY_HIGH; sce->nodetree->render_quality = NTREE_QUALITY_HIGH; - out = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_COMPOSITE); + bNode *out = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_COMPOSITE); out->locx = 300.0f; out->locy = 400.0f; - in = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_R_LAYERS); + bNode *in = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_R_LAYERS); in->locx = 10.0f; in->locy = 400.0f; nodeSetActive(sce->nodetree, in); /* links from color to color */ - fromsock = in->outputs.first; - tosock = out->inputs.first; + bNodeSocket *fromsock = in->outputs.first; + bNodeSocket *tosock = out->inputs.first; nodeAddLink(sce->nodetree, in, fromsock, out, tosock); ntreeUpdateTree(CTX_data_main(C), sce->nodetree); @@ -562,9 +552,6 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce) /* called from shading buttons or header */ void ED_node_texture_default(const bContext *C, Tex *tex) { - bNode *in, *out; - bNodeSocket *fromsock, *tosock; - /* but lets check it anyway */ if (tex->nodetree) { if (G.debug & G_DEBUG) { @@ -575,17 +562,17 @@ void ED_node_texture_default(const bContext *C, Tex *tex) tex->nodetree = ntreeAddTree(NULL, "Texture Nodetree", ntreeType_Texture->idname); - out = nodeAddStaticNode(C, tex->nodetree, TEX_NODE_OUTPUT); + bNode *out = nodeAddStaticNode(C, tex->nodetree, TEX_NODE_OUTPUT); out->locx = 300.0f; out->locy = 300.0f; - in = nodeAddStaticNode(C, tex->nodetree, TEX_NODE_CHECKER); + bNode *in = nodeAddStaticNode(C, tex->nodetree, TEX_NODE_CHECKER); in->locx = 10.0f; in->locy = 300.0f; nodeSetActive(tex->nodetree, in); - fromsock = in->outputs.first; - tosock = out->inputs.first; + bNodeSocket *fromsock = in->outputs.first; + bNodeSocket *tosock = out->inputs.first; nodeAddLink(tex->nodetree, in, fromsock, out, tosock); ntreeUpdateTree(CTX_data_main(C), tex->nodetree); @@ -634,15 +621,13 @@ void snode_set_context(const bContext *C) void snode_update(SpaceNode *snode, bNode *node) { - bNodeTreePath *path; - /* XXX this only updates nodes in the current node space tree path. * The function supposedly should update any potential group node linking to changed tree, * this really requires a working depsgraph ... */ /* update all edited group nodes */ - path = snode->treepath.last; + bNodeTreePath *path = snode->treepath.last; if (path) { bNodeTree *ngroup = path->nodetree; for (path = path->prev; path; path = path->prev) { @@ -671,10 +656,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti /* generic node group output: set node as active output */ if (node->type == NODE_GROUP_OUTPUT) { - bNode *tnode; - for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) { - if (tnode->type == NODE_GROUP_OUTPUT) { - tnode->flag &= ~NODE_DO_OUTPUT; + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (node_iter->type == NODE_GROUP_OUTPUT) { + node_iter->flag &= ~NODE_DO_OUTPUT; } } @@ -696,11 +680,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT, SH_NODE_OUTPUT_LINESTYLE)) { - bNode *tnode; - - for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) { - if (tnode->type == node->type) { - tnode->flag &= ~NODE_DO_OUTPUT; + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (node_iter->type == node->type) { + node_iter->flag &= ~NODE_DO_OUTPUT; } } @@ -715,16 +697,13 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti /* if active texture changed, free glsl materials */ if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) { - Material *ma; - World *wo; - - for (ma = bmain->materials.first; ma; ma = ma->id.next) { + LISTBASE_FOREACH (Material *, ma, &bmain->materials) { if (ma->nodetree && ma->use_nodes && ntreeHasTree(ma->nodetree, ntree)) { GPU_material_free(&ma->gpumaterial); } } - for (wo = bmain->worlds.first; wo; wo = wo->id.next) { + LISTBASE_FOREACH (World *, wo, &bmain->materials) { if (wo->nodetree && wo->use_nodes && ntreeHasTree(wo->nodetree, ntree)) { GPU_material_free(&wo->gpumaterial); } @@ -742,11 +721,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti else if (ntree->type == NTREE_COMPOSIT) { /* make active viewer, currently only 1 supported... */ if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { - bNode *tnode; - - for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) { - if (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { - tnode->flag &= ~NODE_DO_OUTPUT; + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (ELEM(node_iter->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + node_iter->flag &= ~NODE_DO_OUTPUT; } } @@ -760,11 +737,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti } else if (node->type == CMP_NODE_COMPOSITE) { if (was_output == 0) { - bNode *tnode; - - for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) { - if (tnode->type == CMP_NODE_COMPOSITE) { - tnode->flag &= ~NODE_DO_OUTPUT; + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (node_iter->type == CMP_NODE_COMPOSITE) { + node_iter->flag &= ~NODE_DO_OUTPUT; } } @@ -879,14 +854,12 @@ static void edit_node_properties_get( /* is rct in visible part of node? */ static bNode *visible_node(SpaceNode *snode, const rctf *rct) { - bNode *node; - - for (node = snode->edittree->nodes.last; node; node = node->prev) { + LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode->edittree->nodes) { if (BLI_rctf_isect(&node->totr, rct, NULL)) { - break; + return node; } } - return node; + return NULL; } /* ********************** size widget operator ******************** */ @@ -952,23 +925,19 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event) ARegion *region = CTX_wm_region(C); bNode *node = nodeGetActive(snode->edittree); NodeSizeWidget *nsw = op->customdata; - float mx, my, dx, dy; switch (event->type) { - case MOUSEMOVE: - + case MOUSEMOVE: { + float mx, my; UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &mx, &my); - dx = (mx - nsw->mxstart) / UI_DPI_FAC; - dy = (my - nsw->mystart) / UI_DPI_FAC; + float dx = (mx - nsw->mxstart) / UI_DPI_FAC; + float dy = (my - nsw->mystart) / UI_DPI_FAC; if (node) { - float *pwidth; - float oldwidth, widthmin, widthmax; - - pwidth = &node->width; - oldwidth = nsw->oldwidth; - widthmin = node->typeinfo->minwidth; - widthmax = node->typeinfo->maxwidth; + float *pwidth = &node->width; + float oldwidth = nsw->oldwidth; + float widthmin = node->typeinfo->minwidth; + float widthmax = node->typeinfo->maxwidth; { if (nsw->directions & NODE_RESIZE_RIGHT) { @@ -1026,23 +995,24 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event) ED_region_tag_redraw(region); break; - + } case LEFTMOUSE: case MIDDLEMOUSE: - case RIGHTMOUSE: + case RIGHTMOUSE: { if (event->val == KM_RELEASE) { node_resize_exit(C, op, false); ED_node_post_apply_transform(C, snode->edittree); return OPERATOR_FINISHED; } - else if (event->val == KM_PRESS) { + if (event->val == KM_PRESS) { node_resize_exit(C, op, true); ED_region_tag_redraw(region); return OPERATOR_CANCELLED; } break; + } } return OPERATOR_RUNNING_MODAL; @@ -1095,14 +1065,12 @@ void NODE_OT_resize(wmOperatorType *ot) bool node_has_hidden_sockets(bNode *node) { - bNodeSocket *sock; - - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (sock->flag & SOCK_HIDDEN) { return true; } } - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { if (sock->flag & SOCK_HIDDEN) { return true; } @@ -1112,24 +1080,22 @@ bool node_has_hidden_sockets(bNode *node) void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) { - bNodeSocket *sock; - if (set == 0) { - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { sock->flag &= ~SOCK_HIDDEN; } - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { sock->flag &= ~SOCK_HIDDEN; } } else { /* hide unused sockets */ - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (sock->link == NULL) { sock->flag |= SOCK_HIDDEN; } } - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { if (nodeCountSocketLinks(snode->edittree, sock) == 0) { sock->flag |= SOCK_HIDDEN; } @@ -1142,16 +1108,13 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) int node_find_indicated_socket( SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, float cursor[2], int in_out) { - bNode *node; - bNodeSocket *sock; rctf rect; *nodep = NULL; *sockp = NULL; /* check if we click in a socket */ - for (node = snode->edittree->nodes.first; node; node = node->next) { - + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { BLI_rctf_init_pt_radius(&rect, cursor, NODE_SOCKSIZE + 4); if (!(node->flag & NODE_HIDDEN)) { @@ -1167,7 +1130,7 @@ int node_find_indicated_socket( } if (in_out & SOCK_IN) { - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (!nodeSocketIsHidden(sock)) { if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { if (node == visible_node(snode, &rect)) { @@ -1180,7 +1143,7 @@ int node_find_indicated_socket( } } if (in_out & SOCK_OUT) { - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { if (!nodeSocketIsHidden(sock)) { if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { if (node == visible_node(snode, &rect)) { @@ -1226,17 +1189,15 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNode *node, *newnode, *lastnode; - bNodeLink *link, *newlink, *lastlink; const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs"); bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - lastnode = ntree->nodes.last; - for (node = ntree->nodes.first; node; node = node->next) { + bNode *lastnode = ntree->nodes.last; + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { - newnode = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT); + BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT); /* to ensure redraws or rerenders happen */ ED_node_tag_update_id(snode->id); @@ -1251,14 +1212,14 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) /* copy links between selected nodes * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy! */ - lastlink = ntree->links.last; - for (link = ntree->links.first; link; link = link->next) { + bNodeLink *lastlink = ntree->links.last; + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { /* This creates new links between copied nodes. * If keep_inputs is set, also copies input links from unselected (when fromnode==NULL)! */ if (link->tonode && (link->tonode->flag & NODE_SELECT) && (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) { - newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); + bNodeLink *newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); newlink->flag = link->flag; newlink->tonode = link->tonode->new_node; newlink->tosock = link->tosock->new_sock; @@ -1282,11 +1243,11 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) } /* clear flags for recursive depth-first iteration */ - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { node->flag &= ~NODE_TEST; } /* reparent copied nodes */ - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if ((node->flag & SELECT) && !(node->flag & NODE_TEST)) { node_duplicate_reparent_recursive(node); } @@ -1298,10 +1259,10 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) } /* deselect old nodes, select the copies instead */ - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { /* has been set during copy above */ - newnode = node->new_node; + bNode *newnode = node->new_node; nodeSetSelected(node, false); node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE); @@ -1389,17 +1350,16 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - Scene *curscene = CTX_data_scene(C), *scene; - bNode *node; + Scene *curscene = CTX_data_scene(C); ED_preview_kill_jobs(CTX_wm_manager(C), bmain); /* first tag scenes unread */ - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { scene->id.tag |= LIB_TAG_DOIT; } - for (node = snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if (node->type == CMP_NODE_R_LAYERS) { ID *id = node->id; if (id->tag & LIB_TAG_DOIT) { @@ -1434,13 +1394,14 @@ void NODE_OT_read_viewlayers(wmOperatorType *ot) int node_render_changed_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *sce = CTX_data_scene(C); - bNode *node; /* This is actually a test whether scene is used by the compositor or not. * All the nodes are using same render result, so there is no need to do * anything smart about check how exactly scene is used. */ - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == (ID *)sce) { + bNode *node = NULL; + LISTBASE_FOREACH (bNode *, node_iter, &sce->nodetree->nodes) { + if (node_iter->id == (ID *)sce) { + node = node_iter; break; } } @@ -1486,14 +1447,14 @@ void NODE_OT_render_changed(wmOperatorType *ot) static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag) { - bNode *node; int tot_eq = 0, tot_neq = 0; /* Toggles the flag on all selected nodes. * If the flag is set on all nodes it is unset. * If the flag is not set on all nodes, it is set. */ - for (node = snode->edittree->nodes.first; node; node = node->next) { + + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { if (toggle_flag == NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW) == 0) { @@ -1512,7 +1473,7 @@ static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag) } } } - for (node = snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { if (toggle_flag == NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW) == 0) { @@ -1631,8 +1592,6 @@ void NODE_OT_options_toggle(wmOperatorType *ot) static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); - bNode *node; - int hidden; /* sanity checking (poll callback checks this already) */ if ((snode == NULL) || (snode->edittree == NULL)) { @@ -1642,17 +1601,17 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op)) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); /* Toggle for all selected nodes */ - hidden = 0; - for (node = snode->edittree->nodes.first; node; node = node->next) { + bool hidden = false; + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { if (node_has_hidden_sockets(node)) { - hidden = 1; + hidden = true; break; } } } - for (node = snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { node_set_hidden_sockets(snode, node, !hidden); } @@ -1686,12 +1645,11 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - bNode *node; bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - for (node = snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { /* Only allow muting of nodes having a mute func! */ if ((node->flag & SELECT) && node->typeinfo->update_internal_links) { node->flag ^= NODE_MUTED; @@ -1731,13 +1689,11 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - bNode *node, *next; bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - for (node = snode->edittree->nodes.first; node; node = next) { - next = node->next; + LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node)); nodeRemoveNode(bmain, snode->edittree, node, true); @@ -1787,10 +1743,8 @@ static bool node_switch_view_poll(bContext *C) static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); - bNode *node, *next; - for (node = snode->edittree->nodes.first; node; node = next) { - next = node->next; + LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { /* call the update function from the Switch View node */ node->update = NODE_UPDATE_OPERATOR; @@ -1825,12 +1779,10 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - bNode *node, *next; ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - for (node = snode->edittree->nodes.first; node; node = next) { - next = node->next; + LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { nodeInternalRelink(snode->edittree, node); nodeRemoveNode(bmain, snode->edittree, node, true); @@ -1963,9 +1915,6 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); PointerRNA ptr = CTX_data_pointer_get(C, "node"); bNode *node = NULL; - NodeImageMultiFile *nimf; - bNodeSocket *sock; - int direction; if (ptr.data) { node = ptr.data; @@ -1978,14 +1927,14 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - nimf = node->storage; + NodeImageMultiFile *nimf = node->storage; - sock = BLI_findlink(&node->inputs, nimf->active_input); + bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input); if (!sock) { return OPERATOR_CANCELLED; } - direction = RNA_enum_get(op->ptr, "direction"); + int direction = RNA_enum_get(op->ptr, "direction"); if (direction == 1) { bNodeSocket *before = sock->prev; @@ -2037,24 +1986,23 @@ static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNode *node, *tnode; if (!ntree) { return OPERATOR_CANCELLED; } - node = nodeGetActive(ntree); + bNode *node = nodeGetActive(ntree); if (!node) { return OPERATOR_CANCELLED; } - for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) { - if (tnode->flag & NODE_SELECT && tnode != node) { + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (node_iter->flag & NODE_SELECT && node_iter != node) { if (node->flag & NODE_CUSTOM_COLOR) { - tnode->flag |= NODE_CUSTOM_COLOR; - copy_v3_v3(tnode->color, node->color); + node_iter->flag |= NODE_CUSTOM_COLOR; + copy_v3_v3(node_iter->color, node->color); } else { - tnode->flag &= ~NODE_CUSTOM_COLOR; + node_iter->flag &= ~NODE_CUSTOM_COLOR; } } } @@ -2086,8 +2034,6 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNode *node; - bNodeLink *link, *newlink; ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); @@ -2095,7 +2041,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) BKE_node_clipboard_clear(); BKE_node_clipboard_init(ntree); - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { /* No ID refcounting, this node is virtual, * detached from any actual Blender data currently. */ @@ -2105,7 +2051,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) } } - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { bNode *new_node = node->new_node; @@ -2126,11 +2072,11 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) /* copy links between selected nodes * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy! */ - for (link = ntree->links.first; link; link = link->next) { + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { /* This creates new links between copied nodes. */ if (link->tonode && (link->tonode->flag & NODE_SELECT) && link->fromnode && (link->fromnode->flag & NODE_SELECT)) { - newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); + bNodeLink *newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); newlink->flag = link->flag; newlink->tonode = link->tonode->new_node; newlink->tosock = link->tosock->new_sock; @@ -2165,18 +2111,11 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - const ListBase *clipboard_nodes_lb; - const ListBase *clipboard_links_lb; - bNode *node; - bNodeLink *link; - int num_nodes; - float center[2]; - bool is_clipboard_valid, all_nodes_valid; /* validate pointers in the clipboard */ - is_clipboard_valid = BKE_node_clipboard_validate(); - clipboard_nodes_lb = BKE_node_clipboard_get_nodes(); - clipboard_links_lb = BKE_node_clipboard_get_links(); + bool is_clipboard_valid = BKE_node_clipboard_validate(); + const ListBase *clipboard_nodes_lb = BKE_node_clipboard_get_nodes(); + const ListBase *clipboard_links_lb = BKE_node_clipboard_get_links(); if (BLI_listbase_is_empty(clipboard_nodes_lb)) { BKE_report(op->reports, RPT_ERROR, "Clipboard is empty"); @@ -2196,8 +2135,8 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) } /* make sure all clipboard nodes would be valid in the target tree */ - all_nodes_valid = true; - for (node = clipboard_nodes_lb->first; node; node = node->next) { + bool all_nodes_valid = true; + LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { if (!node->typeinfo->poll_instance || !node->typeinfo->poll_instance(node, ntree)) { all_nodes_valid = false; BKE_reportf(op->reports, @@ -2217,15 +2156,16 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) node_deselect_all(snode); /* calculate "barycenter" for placing on mouse cursor */ - zero_v2(center); - for (node = clipboard_nodes_lb->first, num_nodes = 0; node; node = node->next, num_nodes++) { + float center[2] = {0.0f, 0.0f}; + int num_nodes = 0; + LISTBASE_FOREACH_INDEX (bNode *, node, clipboard_nodes_lb, num_nodes) { center[0] += BLI_rctf_cent_x(&node->totr); center[1] += BLI_rctf_cent_y(&node->totr); } mul_v2_fl(center, 1.0 / num_nodes); /* copy nodes from clipboard */ - for (node = clipboard_nodes_lb->first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { bNode *new_node = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT); /* pasted nodes are selected */ @@ -2233,14 +2173,14 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) } /* reparent copied nodes */ - for (node = clipboard_nodes_lb->first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { bNode *new_node = node->new_node; if (new_node->parent) { new_node->parent = new_node->parent->new_node; } } - for (link = clipboard_links_lb->first; link; link = link->next) { + LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) { nodeAddLink(ntree, link->fromnode->new_node, link->fromsock->new_sock, @@ -2275,10 +2215,9 @@ void NODE_OT_clipboard_paste(wmOperatorType *ot) static bNodeSocket *ntree_get_active_interface_socket(ListBase *lb) { - bNodeSocket *sock; - for (sock = lb->first; sock; sock = sock->next) { - if (sock->flag & SELECT) { - return sock; + LISTBASE_FOREACH (bNodeSocket *, socket, lb) { + if (socket->flag & SELECT) { + return socket; } } return NULL; @@ -2289,12 +2228,12 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; int in_out = RNA_enum_get(op->ptr, "in_out"); - PointerRNA ntree_ptr; - bNodeSocket *sock, *tsock, *active_sock; - const char *default_name; + PointerRNA ntree_ptr; RNA_id_pointer_create((ID *)ntree, &ntree_ptr); + const char *default_name; + bNodeSocket *active_sock; if (in_out == SOCK_IN) { active_sock = ntree_get_active_interface_socket(&ntree->inputs); default_name = "Input"; @@ -2304,6 +2243,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op) default_name = "Output"; } + bNodeSocket *sock; if (active_sock) { /* insert a copy of the active socket right after it */ sock = ntreeInsertSocketInterface( @@ -2317,11 +2257,11 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op) } /* deactivate sockets (has to check both lists) */ - for (tsock = ntree->inputs.first; tsock; tsock = tsock->next) { - tsock->flag &= ~SELECT; + LISTBASE_FOREACH (bNodeSocket *, socket_iter, &ntree->inputs) { + socket_iter->flag &= ~SELECT; } - for (tsock = ntree->outputs.first; tsock; tsock = tsock->next) { - tsock->flag &= ~SELECT; + LISTBASE_FOREACH (bNodeSocket *, socket_iter, &ntree->outputs) { + socket_iter->flag &= ~SELECT; } /* make the new socket active */ sock->flag |= SELECT; @@ -2359,9 +2299,8 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNodeSocket *iosock, *active_sock; - iosock = ntree_get_active_interface_socket(&ntree->inputs); + bNodeSocket *iosock = ntree_get_active_interface_socket(&ntree->inputs); if (!iosock) { iosock = ntree_get_active_interface_socket(&ntree->outputs); } @@ -2370,7 +2309,7 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *UNUSED(op)) } /* preferably next socket becomes active, otherwise try previous socket */ - active_sock = (iosock->next ? iosock->next : iosock->prev); + bNodeSocket *active_sock = (iosock->next ? iosock->next : iosock->prev); ntreeRemoveSocketInterface(ntree, iosock); /* set active socket */ @@ -2416,11 +2355,9 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; int direction = RNA_enum_get(op->ptr, "direction"); - bNodeSocket *iosock; - ListBase *lb; - lb = &ntree->inputs; - iosock = ntree_get_active_interface_socket(lb); + ListBase *lb = &ntree->inputs; + bNodeSocket *iosock = ntree_get_active_interface_socket(lb); if (!iosock) { lb = &ntree->outputs; iosock = ntree_get_active_interface_socket(lb); @@ -2489,8 +2426,6 @@ static bool node_shader_script_update_poll(bContext *C) Scene *scene = CTX_data_scene(C); const RenderEngineType *type = RE_engines_find(scene->r.engine); SpaceNode *snode = CTX_wm_space_node(C); - bNode *node; - Text *text; /* test if we have a render engine that supports shaders scripts */ if (!(type && type->update_script_node)) { @@ -2498,7 +2433,7 @@ static bool node_shader_script_update_poll(bContext *C) } /* see if we have a shader script node in context */ - node = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript).data; + bNode *node = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript).data; if (!node && snode && snode->edittree) { node = nodeGetActive(snode->edittree); @@ -2513,7 +2448,7 @@ static bool node_shader_script_update_poll(bContext *C) } /* see if we have a text datablock in context */ - text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data; + Text *text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data; if (text) { return 1; } @@ -2530,12 +2465,11 @@ static bool node_shader_script_update_text_recursive(RenderEngine *engine, Text *text) { bool found = false; - bNode *node; ntree->done = true; /* update each script that is using this text datablock */ - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == NODE_GROUP) { bNodeTree *ngroup = (bNodeTree *)node->id; if (ngroup && !ngroup->done) { @@ -2557,18 +2491,16 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); SpaceNode *snode = CTX_wm_space_node(C); PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript); - bNodeTree *ntree_base = NULL; - bNode *node = NULL; - RenderEngine *engine; - RenderEngineType *type; bool found = false; /* setup render engine */ - type = RE_engines_find(scene->r.engine); - engine = RE_engine_create(type); + RenderEngineType *type = RE_engines_find(scene->r.engine); + RenderEngine *engine = RE_engine_create(type); engine->reports = op->reports; /* get node */ + bNodeTree *ntree_base = NULL; + bNode *node = NULL; if (nodeptr.data) { ntree_base = (bNodeTree *)nodeptr.owner_id; node = nodeptr.data; @@ -2643,10 +2575,8 @@ static void viewer_border_corner_to_backdrop(SpaceNode *snode, float *fx, float *fy) { - float bufx, bufy; - - bufx = backdrop_width * snode->zoom; - bufy = backdrop_height * snode->zoom; + float bufx = backdrop_width * snode->zoom; + float bufy = backdrop_height * snode->zoom; *fx = (bufx > 0.0f ? ((float)x - 0.5f * region->winx - snode->xof) / bufx + 0.5f : 0.0f); *fy = (bufy > 0.0f ? ((float)y - 0.5f * region->winy - snode->yof) / bufy + 0.5f : 0.0f); @@ -2655,14 +2585,12 @@ static void viewer_border_corner_to_backdrop(SpaceNode *snode, static int viewer_border_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Image *ima; void *lock; - ImBuf *ibuf; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); if (ibuf) { ARegion *region = CTX_wm_region(C); diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index 3c861896d37..d2c88ed787c 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -283,7 +283,7 @@ void NODE_OT_backimage_move(wmOperatorType *ot) { /* identifiers */ ot->name = "Background Image Move"; - ot->description = "Move Node backdrop"; + ot->description = "Move node backdrop"; ot->idname = "NODE_OT_backimage_move"; /* api callbacks */ diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index afc1a963f4f..ad7632377a3 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -645,7 +645,7 @@ static bool node_ima_drop_poll(bContext *UNUSED(C), /* rule might not work? */ return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)); } - return WM_drag_ID(drag, ID_IM) != NULL; + return WM_drag_get_local_ID(drag, ID_IM) != NULL; } static bool node_mask_drop_poll(bContext *UNUSED(C), @@ -653,19 +653,19 @@ static bool node_mask_drop_poll(bContext *UNUSED(C), const wmEvent *UNUSED(event), const char **UNUSED(r_tooltip)) { - return WM_drag_ID(drag, ID_MSK) != NULL; + return WM_drag_get_local_ID(drag, ID_MSK) != NULL; } static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID(drag, 0); RNA_string_set(drop->ptr, "name", id->name + 2); } static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID(drag, 0); if (id) { RNA_string_set(drop->ptr, "name", id->name + 2); diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 74f99540bee..e0262371559 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -34,6 +34,7 @@ set(INC set(SRC outliner_collections.c + outliner_context.c outliner_dragdrop.c outliner_draw.c outliner_edit.c @@ -46,12 +47,12 @@ set(SRC space_outliner.c tree/common.cc tree/tree_display.cc + tree/tree_display_data.cc tree/tree_display_libraries.cc - tree/tree_display_view_layer.cc - tree/tree_display_sequencer.cc tree/tree_display_orphaned.cc tree/tree_display_scenes.cc - tree/tree_display_data.cc + tree/tree_display_sequencer.cc + tree/tree_display_view_layer.cc tree/tree_element.cc tree/tree_element_anim_data.cc tree/tree_element_driver_base.cc diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.c new file mode 100644 index 00000000000..a314a640e42 --- /dev/null +++ b/source/blender/editors/space_outliner/outliner_context.c @@ -0,0 +1,73 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_listbase.h" + +#include "BKE_context.h" + +#include "DNA_space_types.h" + +#include "RNA_access.h" + +#include "outliner_intern.h" + +static void outliner_context_selected_ids_recursive(const ListBase *subtree, + bContextDataResult *result) +{ + LISTBASE_FOREACH (const TreeElement *, te, subtree) { + const TreeStoreElem *tse = TREESTORE(te); + if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, 0, TSE_LAYER_COLLECTION))) { + CTX_data_id_list_add(result, tse->id); + } + outliner_context_selected_ids_recursive(&te->subtree, result); + } +} + +static void outliner_context_selected_ids(const SpaceOutliner *space_outliner, + bContextDataResult *result) +{ + outliner_context_selected_ids_recursive(&space_outliner->tree, result); + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); +} + +static const char *outliner_context_dir[] = {"selected_ids", NULL}; + +int /*eContextResult*/ outliner_context(const bContext *C, + const char *member, + bContextDataResult *result) +{ + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + + if (CTX_data_dir(member)) { + CTX_data_dir_set(result, outliner_context_dir); + return CTX_RESULT_OK; + } + if (CTX_data_equals(member, "selected_ids")) { + outliner_context_selected_ids(space_outliner, result); + return CTX_RESULT_OK; + } + /* Note: Querying non-ID selection could also work if tree elements stored their matching RNA + * struct type. */ + + return CTX_RESULT_MEMBER_NOT_FOUND; +} diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index d3da7b80765..152bbc96281 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -333,7 +333,7 @@ static bool parent_drop_poll(bContext *C, ED_region_tag_redraw_no_rebuild(CTX_wm_region(C)); } - Object *potential_child = (Object *)WM_drag_ID(drag, ID_OB); + Object *potential_child = (Object *)WM_drag_get_local_ID(drag, ID_OB); if (!potential_child) { return false; } @@ -421,7 +421,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) } Object *par = (Object *)tselem->id; - Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); + Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB); if (ELEM(NULL, ob, par)) { return OPERATOR_CANCELLED; @@ -445,7 +445,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) void OUTLINER_OT_parent_drop(wmOperatorType *ot) { /* identifiers */ - ot->name = "Drop to Set Parent [+Alt keeps transforms]"; + ot->name = "Drop to Set Parent (hold Alt to keep transforms)"; ot->description = "Drag to parent in Outliner"; ot->idname = "OUTLINER_OT_parent_drop"; @@ -473,7 +473,7 @@ static bool parent_clear_poll(bContext *C, } } - Object *ob = (Object *)WM_drag_ID(drag, ID_OB); + Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB); if (!ob) { return false; } @@ -531,7 +531,7 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven void OUTLINER_OT_parent_clear(wmOperatorType *ot) { /* identifiers */ - ot->name = "Drop to Clear Parent [+Alt keeps transforms]"; + ot->name = "Drop to Clear Parent (hold Alt to keep transforms)"; ot->description = "Drag to clear parent in Outliner"; ot->idname = "OUTLINER_OT_parent_clear"; @@ -552,7 +552,7 @@ static bool scene_drop_poll(bContext *C, const char **UNUSED(r_tooltip)) { /* Ensure item under cursor is valid drop target */ - Object *ob = (Object *)WM_drag_ID(drag, ID_OB); + Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB); return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL)); } @@ -560,7 +560,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent { Main *bmain = CTX_data_main(C); Scene *scene = (Scene *)outliner_ID_drop_find(C, event, ID_SCE); - Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); + Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB); if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) { return OPERATOR_CANCELLED; @@ -620,7 +620,7 @@ static bool material_drop_poll(bContext *C, const char **UNUSED(r_tooltip)) { /* Ensure item under cursor is valid drop target */ - Material *ma = (Material *)WM_drag_ID(drag, ID_MA); + Material *ma = (Material *)WM_drag_get_local_ID(drag, ID_MA); return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL)); } @@ -628,7 +628,7 @@ static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve { Main *bmain = CTX_data_main(C); Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB); - Material *ma = (Material *)WM_drag_ID_from_event(event, ID_MA); + Material *ma = (Material *)WM_drag_get_local_ID_from_event(event, ID_MA); if (ELEM(NULL, ob, ma)) { return OPERATOR_CANCELLED; @@ -1461,14 +1461,14 @@ static int outliner_item_drag_drop_invoke(bContext *C, parent = scene->master_collection; } - WM_drag_add_ID(drag, id, &parent->id); + WM_drag_add_local_ID(drag, id, &parent->id); } BLI_freelistN(&selected.selected_array); } else { /* Add single ID. */ - WM_drag_add_ID(drag, data.drag_id, data.drag_parent); + WM_drag_add_local_ID(drag, data.drag_id, data.drag_parent); } ED_outliner_select_sync_from_outliner(C, space_outliner); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 6364fbc0a87..9223da136e1 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1996,7 +1996,7 @@ static void outliner_draw_mode_column_toggle(uiBlock *block, "Change the object in the current mode\n" "* Ctrl to add to the current mode"); } - + UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); uiBut *but = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, @@ -2845,6 +2845,7 @@ static void outliner_draw_iconrow(bContext *C, LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); + te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED); /* object hierarchy always, further constrained on level */ if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) { @@ -2928,8 +2929,6 @@ static void outliner_draw_iconrow(bContext *C, /* closed tree element */ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int starty) { - TreeElement *ten; - /* closed items may be displayed in row of parent, don't change their coordinate! */ if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) { te->xs = 0; @@ -2937,7 +2936,7 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta te->xend = 0; } - for (ten = te->subtree.first; ten; ten = ten->next) { + LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) { outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty); } } @@ -3647,7 +3646,7 @@ void draw_outliner(const bContext *C) outliner_tree_dimensions(space_outliner, &tree_width, &tree_height); /* Default to no emboss for outliner UI. */ - UI_block_emboss_set(block, UI_EMBOSS_NONE); + UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); if (space_outliner->outlinevis == SO_DATA_API) { int buttons_start_x = outliner_data_api_buttons_start_x(tree_width); @@ -3656,7 +3655,7 @@ void draw_outliner(const bContext *C) UI_block_emboss_set(block, UI_EMBOSS); outliner_draw_rnabuts(block, region, space_outliner, buttons_start_x, &space_outliner->tree); - UI_block_emboss_set(block, UI_EMBOSS_NONE); + UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); } else if (space_outliner->outlinevis == SO_ID_ORPHANS) { /* draw user toggle columns */ diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index a1ff6193cd0..1cb98e704f2 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -1253,8 +1253,7 @@ static void outliner_set_coordinates_element_recursive(SpaceOutliner *space_outl *starty -= UI_UNIT_Y; if (TSELEM_OPEN(tselem, space_outliner)) { - TreeElement *ten; - for (ten = te->subtree.first; ten; ten = ten->next) { + LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) { outliner_set_coordinates_element_recursive(space_outliner, ten, startx + UI_UNIT_X, starty); } } @@ -1753,7 +1752,7 @@ static void tree_element_to_path(TreeElement *te, { ListBase hierarchy = {NULL, NULL}; LinkData *ld; - TreeElement *tem, *temnext, *temsub; + TreeElement *tem, *temnext; TreeStoreElem *tse /* , *tsenext */ /* UNUSED */; PointerRNA *ptr, *nextptr; PropertyRNA *prop; @@ -1823,7 +1822,7 @@ static void tree_element_to_path(TreeElement *te, /* otherwise use index */ int index = 0; - for (temsub = tem->subtree.first; temsub; temsub = temsub->next, index++) { + LISTBASE_FOREACH (TreeElement *, temsub, &tem->subtree) { if (temsub == temnext) { break; } diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 0294b4836c8..339cc3068d0 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -42,6 +42,7 @@ struct TreeElement; struct TreeStoreElem; struct ViewLayer; struct bContext; +struct bContextDataResult; struct bPoseChannel; struct wmKeyConfig; struct wmOperatorType; @@ -561,6 +562,12 @@ void outliner_tag_redraw_avoid_rebuild_on_open_change(const struct SpaceOutliner void outliner_sync_selection(const struct bContext *C, struct SpaceOutliner *space_outliner); +/* outliner_context.c ------------------------------------------- */ + +int outliner_context(const struct bContext *C, + const char *member, + struct bContextDataResult *result); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index fa8bce9df6a..6380bb9505e 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -72,6 +72,7 @@ #include "ED_sequencer.h" #include "ED_undo.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" #include "WM_api.h" @@ -870,13 +871,13 @@ static eOLDrawState tree_element_active_sequence(bContext *C, const eOLSetState set) { Sequence *seq = (Sequence *)te->directdata; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (set != OL_SETSEL_NONE) { /* only check on setting */ if (BLI_findindex(ed->seqbasep, seq) != -1) { if (set == OL_SETSEL_EXTEND) { - BKE_sequencer_active_set(scene, NULL); + SEQ_select_active_set(scene, NULL); } ED_sequencer_deselect_all(scene); @@ -885,7 +886,7 @@ static eOLDrawState tree_element_active_sequence(bContext *C, } else { seq->flag |= SELECT; - BKE_sequencer_active_set(scene, seq); + SEQ_select_active_set(scene, seq); } } @@ -905,7 +906,7 @@ static eOLDrawState tree_element_active_sequence_dup(Scene *scene, const eOLSetState set) { Sequence *seq, *p; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); seq = (Sequence *)te->directdata; if (set == OL_SETSEL_NONE) { @@ -1185,6 +1186,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } else { ModifierData *md = (ModifierData *)te->directdata; + BKE_object_modifier_set_active(ob, md); switch ((ModifierType)md->type) { case eModifierType_ParticleSystem: diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c index 0f5c74a9168..0b2d1ce34ec 100644 --- a/source/blender/editors/space_outliner/outliner_sync.c +++ b/source/blender/editors/space_outliner/outliner_sync.c @@ -46,7 +46,7 @@ #include "ED_object.h" #include "ED_outliner.h" -#include "SEQ_sequencer.h" +#include "SEQ_select.h" #include "WM_api.h" #include "WM_types.h" @@ -305,7 +305,7 @@ static void outliner_select_sync_to_sequence(Scene *scene, TreeStoreElem *tselem Sequence *seq = (Sequence *)tselem->id; if (tselem->flag & TSE_ACTIVE) { - BKE_sequencer_active_set(scene, seq); + SEQ_select_active_set(scene, seq); } if (tselem->flag & TSE_SELECTED) { @@ -542,7 +542,7 @@ static void get_sync_select_active_data(const bContext *C, SyncSelectActiveData active_data->object = OBACT(view_layer); active_data->edit_bone = CTX_data_active_bone(C); active_data->pose_channel = CTX_data_active_pose_bone(C); - active_data->sequence = BKE_sequencer_active_get(scene); + active_data->sequence = SEQ_select_active_get(scene); } /* If outliner is dirty sync selection from view layer and sequwncer */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 159a4616ba7..d4784a509bf 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -737,7 +737,7 @@ static void id_local_fn(bContext *C, } static void object_proxy_to_override_convert_fn(bContext *C, - ReportList *UNUSED(reports), + ReportList *reports, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), @@ -754,8 +754,15 @@ static void object_proxy_to_override_convert_fn(bContext *C, return; } - BKE_lib_override_library_proxy_convert( - CTX_data_main(C), scene, CTX_data_view_layer(C), ob_proxy); + if (!BKE_lib_override_library_proxy_convert( + CTX_data_main(C), scene, CTX_data_view_layer(C), ob_proxy)) { + BKE_reportf( + reports, + RPT_ERROR_INVALID_INPUT, + "Could not create a library override from proxy '%s' (might use already local data?)", + ob_proxy->id.name + 2); + return; + } DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_WINDOW, NULL); @@ -1199,7 +1206,7 @@ static void sequence_fn(int event, TreeElement *te, TreeStoreElem *tselem, void Sequence *seq = (Sequence *)te->directdata; if (event == OL_DOP_SELECT) { Scene *scene = (Scene *)scene_ptr; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (BLI_findindex(ed->seqbasep, seq) != -1) { ED_sequencer_select_sequence_single(scene, seq, true); } @@ -1685,6 +1692,8 @@ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_INVALID = 0, OUTLINER_IDOP_UNLINK, + OUTLINER_IDOP_MARK_ASSET, + OUTLINER_IDOP_CLEAR_ASSET, OUTLINER_IDOP_LOCAL, OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE, OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY, @@ -1710,6 +1719,8 @@ typedef enum eOutlinerIdOpTypes { /* TODO: implement support for changing the ID-block used. */ static const EnumPropertyItem prop_id_op_types[] = { {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""}, + {OUTLINER_IDOP_MARK_ASSET, "MARK_ASSET", 0, "Mark Asset", ""}, + {OUTLINER_IDOP_CLEAR_ASSET, "CLEAR_ASSET", 0, "Clear Asset", ""}, {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""}, {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""}, {OUTLINER_IDOP_DELETE, "DELETE", ICON_X, "Delete", ""}, @@ -1915,6 +1926,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) } break; } + case OUTLINER_IDOP_MARK_ASSET: { + WM_operator_name_call(C, "ASSET_OT_mark", WM_OP_EXEC_DEFAULT, NULL); + break; + } + case OUTLINER_IDOP_CLEAR_ASSET: { + WM_operator_name_call(C, "ASSET_OT_clear", WM_OP_EXEC_DEFAULT, NULL); + break; + } case OUTLINER_IDOP_LOCAL: { /* make local */ outliner_do_libdata_operation( @@ -2791,7 +2810,7 @@ static int do_outliner_operation_event(bContext *C, } if (datalevel == TSE_ID_BASE) { /* do nothing... there are no ops needed here yet */ - return 0; + return OPERATOR_CANCELLED; } if (datalevel == TSE_CONSTRAINT) { return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation"); @@ -2802,7 +2821,7 @@ static int do_outliner_operation_event(bContext *C, return outliner_operator_menu(C, "OUTLINER_OT_data_operation"); } - return 0; + return OPERATOR_CANCELLED; } static int outliner_operation(bContext *C, wmOperator *op, const wmEvent *event) diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 7308b161d18..56eedcd3748 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -908,9 +908,9 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, /** * TODO: this function needs to be split up! It's getting a bit too large... * - * \note: "ID" is not always a real ID - * \note: If child items are only added to the tree if the item is open, the TSE_ type _must_ be - * added to #outliner_element_needs_rebuild_on_open_change(). + * \note "ID" is not always a real ID. + * \note If child items are only added to the tree if the item is open, + * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change(). */ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, ListBase *lb, diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 3d675fdd9e4..c7c207caca0 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -451,6 +451,7 @@ void ED_spacetype_outliner(void) st->dropboxes = outliner_dropboxes; st->id_remap = outliner_id_remap; st->deactivate = outliner_deactivate; + st->context = outliner_context; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region"); diff --git a/source/blender/editors/space_outliner/tree/tree_display_data.cc b/source/blender/editors/space_outliner/tree/tree_display_data.cc index 41ca4f72903..8a5c2e7d9f3 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_data.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_data.cc @@ -41,7 +41,7 @@ ListBase TreeDisplayDataAPI::buildTree(const TreeSourceData &source_data) RNA_main_pointer_create(source_data.bmain, &mainptr); TreeElement *te = outliner_add_element( - &space_outliner_, &tree, (void *)&mainptr, NULL, TSE_RNA_STRUCT, -1); + &space_outliner_, &tree, (void *)&mainptr, nullptr, TSE_RNA_STRUCT, -1); /* On first view open parent data elements */ const int show_opened = !space_outliner_.treestore || diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc index bd0870c837c..cb5f42f08e1 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc @@ -24,6 +24,8 @@ #include "BKE_collection.h" #include "BKE_main.h" +#include "DNA_collection_types.h" + #include "BLT_translation.h" #include "../outliner_intern.h" diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc index 71c1d344057..0b17ea98831 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc @@ -68,7 +68,7 @@ ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data) TreeElement *te = nullptr; if (!filter_id_type) { ID *id = (ID *)lbarray[a]->first; - te = outliner_add_element(&space_outliner_, &tree, lbarray[a], NULL, TSE_ID_BASE, 0); + te = outliner_add_element(&space_outliner_, &tree, lbarray[a], nullptr, TSE_ID_BASE, 0); te->directdata = lbarray[a]; te->name = outliner_idcode_to_plural(GS(id->name)); } diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc index c4a5688504d..f377512d81e 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc @@ -46,7 +46,7 @@ ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data) for (ID *id : List<ID>(source_data.bmain->scenes)) { Scene *scene = reinterpret_cast<Scene *>(id); - TreeElement *te = outliner_add_element(&space_outliner_, &tree, scene, NULL, 0, 0); + TreeElement *te = outliner_add_element(&space_outliner_, &tree, scene, nullptr, 0, 0); TreeStoreElem *tselem = TREESTORE(te); /* New scene elements open by default */ @@ -60,4 +60,4 @@ ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data) return tree; } -} // namespace blender::ed::outliner
\ No newline at end of file +} // namespace blender::ed::outliner 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 486f735be9f..40f329d72c3 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc @@ -18,7 +18,7 @@ * \ingroup spoutliner */ -#include <string.h> +#include <cstring> #include "BLI_listbase.h" #include "BLI_listbase_wrapper.hh" @@ -43,7 +43,7 @@ ListBase TreeDisplaySequencer::buildTree(const TreeSourceData &source_data) { ListBase tree = {nullptr}; - Editing *ed = BKE_sequencer_editing_get(source_data.scene, false); + Editing *ed = SEQ_editing_get(source_data.scene, false); if (ed == nullptr) { return tree; } @@ -51,11 +51,11 @@ ListBase TreeDisplaySequencer::buildTree(const TreeSourceData &source_data) for (Sequence *seq : List<Sequence>(ed->seqbasep)) { SequenceAddOp op = need_add_seq_dup(seq); if (op == SEQUENCE_DUPLICATE_NONE) { - outliner_add_element(&space_outliner_, &tree, seq, NULL, TSE_SEQUENCE, 0); + outliner_add_element(&space_outliner_, &tree, seq, nullptr, TSE_SEQUENCE, 0); } else if (op == SEQUENCE_DUPLICATE_ADD) { TreeElement *te = outliner_add_element( - &space_outliner_, &tree, seq, NULL, TSE_SEQUENCE_DUP, 0); + &space_outliner_, &tree, seq, nullptr, TSE_SEQUENCE_DUP, 0); add_seq_dup(seq, te, 0); } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc index c88eb957dd1..f7740f4648f 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc @@ -20,6 +20,7 @@ #include <iostream> +#include "DNA_collection_types.h" #include "DNA_scene_types.h" #include "BKE_layer.h" diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h index 9012321a323..d88c37180b3 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.h +++ b/source/blender/editors/space_outliner/tree/tree_element.h @@ -36,7 +36,7 @@ extern "C" { typedef struct TreeElementType TreeElementType; TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv); -void outliner_tree_element_type_free(TreeElementType **element); +void outliner_tree_element_type_free(TreeElementType **type); void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner); diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.hh b/source/blender/editors/space_outliner/tree/tree_element_nla.hh index 3ca62b13bd8..c94287ce576 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_nla.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_nla.hh @@ -23,7 +23,6 @@ #include "tree_element.hh" struct NlaTrack; -struct NlaStrip; namespace blender::ed::outliner { diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c index bde7bdb77f1..50cfa2e71c7 100644 --- a/source/blender/editors/space_script/script_edit.c +++ b/source/blender/editors/space_script/script_edit.c @@ -152,7 +152,7 @@ void SCRIPT_OT_reload(wmOperatorType *ot) { /* identifiers */ ot->name = "Reload Scripts"; - ot->description = "Reload Scripts"; + ot->description = "Reload scripts"; ot->idname = "SCRIPT_OT_reload"; /* api callbacks */ diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 37dfcdbc765..f9076145f2f 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -50,7 +50,15 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "SEQ_add.h" +#include "SEQ_effects.h" +#include "SEQ_relations.h" +#include "SEQ_render.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" +#include "SEQ_utils.h" /* For menu, popup, icons, etc. */ #include "ED_screen.h" @@ -81,9 +89,18 @@ typedef struct SequencerAddData { #define SEQPROP_ENDFRAME (1 << 1) #define SEQPROP_NOPATHS (1 << 2) #define SEQPROP_NOCHAN (1 << 3) +#define SEQPROP_FIT_METHOD (1 << 4) #define SELECT 1 +static const EnumPropertyItem scale_fit_methods[] = { + {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"}, + {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image to completely fill the canvas"}, + {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image to fill the canvas"}, + {SEQ_USE_ORIGINAL_SIZE, "ORIGINAL", 0, "Use Original Size", "Keep image at its original size"}, + {0, NULL, 0, NULL, NULL}, +}; + static void sequencer_generic_props__internal(wmOperatorType *ot, int flag) { PropertyRNA *prop; @@ -123,6 +140,15 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag) prop = RNA_def_boolean( ot->srna, "overlap", 0, "Allow Overlap", "Don't correct overlap on new sequence strips"); RNA_def_property_flag(prop, PROP_HIDDEN); + + if (flag & SEQPROP_FIT_METHOD) { + ot->prop = RNA_def_enum(ot->srna, + "fit_method", + scale_fit_methods, + SEQ_SCALE_TO_FIT, + "Fit Method", + "Scale fit method"); + } } static void sequencer_generic_invoke_path__internal(bContext *C, @@ -131,7 +157,7 @@ static void sequencer_generic_invoke_path__internal(bContext *C, { if (RNA_struct_find_property(op->ptr, identifier)) { Scene *scene = CTX_data_scene(C); - Sequence *last_seq = BKE_sequencer_active_get(scene); + Sequence *last_seq = SEQ_select_active_get(scene); if (last_seq && last_seq->strip && SEQ_HAS_PATH(last_seq)) { Main *bmain = CTX_data_main(C); char path[FILE_MAX]; @@ -147,7 +173,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 = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); int timeline_frame = (int)CFRA; int proximity = INT_MAX; @@ -206,6 +232,8 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato seq_load->end_frame = seq_load->start_frame; seq_load->channel = RNA_int_get(op->ptr, "channel"); seq_load->len = 1; + seq_load->fit_method = RNA_enum_get(op->ptr, "fit_method"); + SEQ_tool_settings_fit_method_set(CTX_data_scene(C), seq_load->fit_method); if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { /* Full path, file is set by the caller. */ @@ -286,11 +314,11 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato static void sequencer_add_apply_overlap(bContext *C, wmOperator *op, Sequence *seq) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (RNA_boolean_get(op->ptr, "overlap") == false) { - if (BKE_sequence_test_overlap(ed->seqbasep, seq)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); } } } @@ -301,7 +329,7 @@ static void sequencer_add_apply_replace_sel(bContext *C, wmOperator *op, Sequenc if (RNA_boolean_get(op->ptr, "replace_sel")) { ED_sequencer_deselect_all(scene); - BKE_sequencer_active_set(scene, seq); + SEQ_select_active_set(scene, seq); seq->flag |= SELECT; } } @@ -314,7 +342,7 @@ static bool seq_effect_add_properties_poll(const bContext *UNUSED(C), int type = RNA_enum_get(op->ptr, "type"); /* Hide start/end frames for effect strips that are locked to their parents' location. */ - if (BKE_sequence_effect_get_num_inputs(type) != 0) { + if (SEQ_effect_get_num_inputs(type) != 0) { if (STR_ELEM(prop_id, "frame_start", "frame_end")) { return false; } @@ -330,7 +358,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); Scene *sce_seq; Sequence *seq; @@ -344,20 +372,20 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE); + seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE); seq->blend_mode = SEQ_TYPE_CROSS; seq->scene = sce_seq; seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1; BLI_strncpy(seq->name + 2, sce_seq->id.name + 2, sizeof(seq->name) - 2); - BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); + SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); - BKE_sequence_calc_disp(scene, seq); - BKE_sequencer_sort(scene); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_sort(scene); sequencer_add_apply_replace_sel(C, op, seq); sequencer_add_apply_overlap(C, op, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); DEG_relations_tag_update(bmain); @@ -404,7 +432,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); MovieClip *clip; Sequence *seq; @@ -418,7 +446,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP); + seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP); seq->blend_mode = SEQ_TYPE_CROSS; seq->clip = clip; seq->len = BKE_movieclip_get_duration(clip); @@ -426,14 +454,14 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op) id_us_ensure_real(&seq->clip->id); BLI_strncpy(seq->name + 2, clip->id.name + 2, sizeof(seq->name) - 2); - BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); + SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); - BKE_sequence_calc_disp(scene, seq); - BKE_sequencer_sort(scene); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_sort(scene); sequencer_add_apply_replace_sel(C, op, seq); sequencer_add_apply_overlap(C, op, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -480,7 +508,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); Mask *mask; Sequence *seq; @@ -494,7 +522,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK); + seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK); seq->blend_mode = SEQ_TYPE_CROSS; seq->mask = mask; seq->len = BKE_mask_get_duration(mask); @@ -502,14 +530,14 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op) id_us_ensure_real(&seq->mask->id); BLI_strncpy(seq->name + 2, mask->id.name + 2, sizeof(seq->name) - 2); - BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); + SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); - BKE_sequence_calc_disp(scene, seq); - BKE_sequencer_sort(scene); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_sort(scene); sequencer_add_apply_replace_sel(C, op, seq); sequencer_add_apply_overlap(C, op, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -554,7 +582,7 @@ void SEQUENCER_OT_mask_strip_add(struct wmOperatorType *ot) static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoadFn seq_load_fn) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); SeqLoadInfo seq_load; int tot_files; @@ -612,7 +640,7 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad return OPERATOR_CANCELLED; } - BKE_sequencer_sort(scene); + SEQ_sort(scene); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -644,7 +672,7 @@ static bool sequencer_add_draw_check_fn(PointerRNA *UNUSED(ptr), static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op) { - return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_movie_strip); + return sequencer_add_generic_strip_exec(C, op, SEQ_add_movie_strip); } static int sequencer_add_movie_strip_invoke(bContext *C, @@ -653,12 +681,13 @@ static int sequencer_add_movie_strip_invoke(bContext *C, { PropertyRNA *prop; Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); /* Only enable "use_framerate" if there aren't any existing strips, unless overridden by user. */ if (ed && ed->seqbasep && ed->seqbasep->first) { RNA_boolean_set(op->ptr, "use_framerate", false); } + RNA_enum_set(op->ptr, "fit_method", SEQ_tool_settings_fit_method_get(scene)); /* This is for drag and drop. */ if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) || @@ -725,7 +754,7 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot) WM_FILESEL_SHOW_PROPS | WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); - sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME); + sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_FIT_METHOD); RNA_def_boolean(ot->srna, "sound", true, "Sound", "Load sound with the movie"); RNA_def_boolean(ot->srna, "use_framerate", @@ -736,7 +765,7 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot) static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op) { - return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_sound_strip); + return sequencer_add_generic_strip_exec(C, op, SEQ_add_sound_strip); } static int sequencer_add_sound_strip_invoke(bContext *C, @@ -850,7 +879,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) { int minframe, numdigits; Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); SeqLoadInfo seq_load; Sequence *seq; Strip *strip; @@ -878,7 +907,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) } /* Main adding function. */ - seq = BKE_sequencer_add_image_strip(C, ed->seqbasep, &seq_load); + seq = SEQ_add_image_strip(C, ed->seqbasep, &seq_load); strip = seq->strip; se = strip->stripdata; seq->blend_mode = SEQ_TYPE_ALPHAOVER; @@ -903,8 +932,8 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) } SEQ_render_init_colorspace(seq); - BKE_sequence_calc_disp(scene, seq); - BKE_sequencer_sort(scene); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_sort(scene); /* Last active name. */ BLI_strncpy(ed->act_imagedir, strip->dir, sizeof(ed->act_imagedir)); @@ -914,7 +943,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) MEM_freeN(op->customdata); } - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -928,6 +957,9 @@ static int sequencer_add_image_strip_invoke(bContext *C, PropertyRNA *prop; Scene *scene = CTX_data_scene(C); + const SequencerToolSettings *tool_settings = scene->toolsettings->sequencer_tool_settings; + RNA_enum_set(op->ptr, "fit_method", tool_settings->fit_method); + /* Name set already by drag and drop. */ if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) { sequencer_generic_invoke_xy__internal( @@ -972,7 +1004,8 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot) WM_FILESEL_SHOW_PROPS | WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); - sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME); + sequencer_generic_props__internal(ot, + SEQPROP_STARTFRAME | SEQPROP_ENDFRAME | SEQPROP_FIT_METHOD); RNA_def_boolean(ot->srna, "use_placeholders", @@ -984,7 +1017,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 = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); Sequence *seq; struct SeqEffectHandle sh; Sequence *seq1, *seq2, *seq3; @@ -1007,11 +1040,11 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) RNA_int_set(op->ptr, "frame_end", end_frame); } - seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, type); - BLI_strncpy(seq->name + 2, BKE_sequence_give_name(seq), sizeof(seq->name) - 2); - BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); + seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, type); + BLI_strncpy(seq->name + 2, SEQ_sequence_give_name(seq), sizeof(seq->name) - 2); + SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); - sh = BKE_sequence_get_effect(seq); + sh = SEQ_effect_handle_get(seq); sh.init(seq); seq->seq1 = seq1; seq->seq2 = seq2; @@ -1019,11 +1052,11 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) if (!seq1) { seq->len = 1; /* Effect is generator, set non zero length. */ - BKE_sequence_tx_set_final_right(seq, end_frame); + SEQ_transform_set_right_handle_frame(seq, end_frame); } seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE; - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); if (seq->type == SEQ_TYPE_COLOR) { SolidColorVars *colvars = (SolidColorVars *)seq->effectdata; @@ -1052,10 +1085,10 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) sequencer_add_apply_replace_sel(C, op, seq); sequencer_add_apply_overlap(C, op, seq); - BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs BKE_sequence_calc. */ - BKE_sequencer_sort(scene); + SEQ_relations_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs SEQ_time_update_sequence. */ + SEQ_sort(scene); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1075,7 +1108,7 @@ static int sequencer_add_effect_strip_invoke(bContext *C, /* When invoking an effect strip which uses inputs, skip initializing the channel from the * mouse. */ - if (BKE_sequence_effect_get_num_inputs(type) != 0) { + if (SEQ_effect_get_num_inputs(type) != 0) { prop_flag |= SEQPROP_NOCHAN; } } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 081714991ff..2ee0dcea5e5 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -68,7 +68,16 @@ #include "BIF_glutil.h" +#include "SEQ_effects.h" +#include "SEQ_prefetch.h" +#include "SEQ_proxy.h" +#include "SEQ_relations.h" +#include "SEQ_render.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" +#include "SEQ_utils.h" #include "UI_interface.h" #include "UI_resources.h" @@ -227,16 +236,16 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, uchar col[3]) * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2. * \param stepsize: The width of a pixel. */ -static void draw_seq_waveform(View2D *v2d, - const bContext *C, - SpaceSeq *sseq, - Scene *scene, - Sequence *seq, - float x1, - float y1, - float x2, - float y2, - float stepsize) +static void draw_seq_waveform_overlay(View2D *v2d, + const bContext *C, + SpaceSeq *sseq, + Scene *scene, + Sequence *seq, + float x1, + float y1, + float x2, + float y2, + float stepsize) { /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */ int x1_offset = max_ff(v2d->cur.xmin, x1); @@ -371,7 +380,7 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, ListBase *seqbase; int offset; - seqbase = BKE_sequence_seqbase_get(seqm, &offset); + seqbase = SEQ_get_seqbase_from_sequence(seqm, &offset); if (!seqbase || BLI_listbase_is_empty(seqbase)) { return; } @@ -488,7 +497,7 @@ static void draw_seq_handle(View2D *v2d, whichsel = SEQ_RIGHTSEL; } - if (!(seq->type & SEQ_TYPE_EFFECT) || BKE_sequence_effect_get_num_inputs(seq->type) == 0) { + if (!(seq->type & SEQ_TYPE_EFFECT) || SEQ_effect_get_num_inputs(seq->type) == 0) { GPU_blend(GPU_BLEND_ALPHA); GPU_blend(GPU_BLEND_ALPHA); @@ -603,121 +612,110 @@ static void draw_seq_outline(Sequence *seq, } } -/* Draw info text on a sequence strip. */ -static void draw_seq_text(View2D *v2d, - Sequence *seq, - SpaceSeq *sseq, - float x1, - float x2, - float y1, - float y2, - bool seq_active, - bool y_threshold) +static const char *draw_seq_text_get_name(Sequence *seq) { - rctf rect; - char str[32 + FILE_MAX]; - size_t str_len; const char *name = seq->name + 2; - uchar col[4]; - - /* All strings should include name. */ if (name[0] == '\0') { - name = BKE_sequence_give_name(seq); + name = SEQ_sequence_give_name(seq); } + return name; +} - if (ELEM(seq->type, SEQ_TYPE_META, SEQ_TYPE_ADJUSTMENT)) { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); +static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t source_len) +{ + /* Set source for the most common types. */ + if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) { + BLI_snprintf(r_source, source_len, "%s%s", seq->strip->dir, seq->strip->stripdata->name); } - else if (seq->type == SEQ_TYPE_SCENE) { - if (seq->scene) { - if (seq->scene_camera) { - str_len = BLI_snprintf(str, - sizeof(str), - "%s: %s (%s) | %d", - name, - seq->scene->id.name + 2, - ((ID *)seq->scene_camera)->name + 2, - seq->len); - } - else { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->scene->id.name + 2, seq->len); - } - } - else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + else if (seq->type == SEQ_TYPE_SOUND_RAM) { + if (seq->sound) { + BLI_snprintf(r_source, source_len, "%s", seq->sound->filepath); } } - else if (seq->type == SEQ_TYPE_MOVIECLIP) { - if (seq->clip && !STREQ(name, seq->clip->id.name + 2)) { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->clip->id.name + 2, seq->len); - } - else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); - } + else if (seq->type == SEQ_TYPE_MULTICAM) { + BLI_snprintf(r_source, source_len, "Channel: %d", seq->multicam_source); } - else if (seq->type == SEQ_TYPE_MASK) { - if (seq->mask && !STREQ(name, seq->mask->id.name + 2)) { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->mask->id.name + 2, seq->len); + else if (seq->type == SEQ_TYPE_TEXT) { + TextVars *textdata = seq->effectdata; + BLI_snprintf(r_source, source_len, "%s", textdata->text); + } + else if (seq->type == SEQ_TYPE_SCENE) { + if (seq->scene_camera) { + BLI_snprintf(r_source, + source_len, + "%s (%s)", + seq->scene->id.name + 2, + ((ID *)seq->scene_camera)->name + 2); } else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + BLI_snprintf(r_source, source_len, "%s", seq->scene->id.name + 2); } } - else if (seq->type == SEQ_TYPE_MULTICAM) { - str_len = BLI_snprintf(str, sizeof(str), "Cam %s: %d", name, seq->multicam_source); - } - else if (seq->type == SEQ_TYPE_IMAGE) { - str_len = BLI_snprintf(str, - sizeof(str), - "%s: %s%s | %d", - name, - seq->strip->dir, - seq->strip->stripdata->name, - seq->len); + else if (seq->type == SEQ_TYPE_MOVIECLIP) { + BLI_snprintf(r_source, source_len, "%s", seq->clip->id.name + 2); } - else if (seq->type == SEQ_TYPE_TEXT) { - TextVars *textdata = seq->effectdata; - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", textdata->text, seq->startdisp); + else if (seq->type == SEQ_TYPE_MASK) { + BLI_snprintf(r_source, source_len, "%s", seq->mask->id.name + 2); } - else if (seq->type & SEQ_TYPE_EFFECT) { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + else { + *r_source = '\0'; } - else if (seq->type == SEQ_TYPE_SOUND_RAM) { - /* If a waveform is drawn, avoid to draw text when there is not enough vertical space. */ - if (!y_threshold && (sseq->flag & SEQ_NO_WAVEFORMS) == 0 && - ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) { +} - str[0] = 0; - str_len = 0; - } - else if (seq->sound) { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->sound->filepath, seq->len); +static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq, + Sequence *seq, + char *r_overlay_string, + size_t overlay_string_len) +{ + const char *name = draw_seq_text_get_name(seq); + char source[FILE_MAX]; + int strip_duration = seq->enddisp - seq->startdisp; + draw_seq_text_get_source(seq, source, sizeof(source)); + + bool show_name = sseq->flag & SEQ_SHOW_STRIP_NAME; + bool show_source = (sseq->flag & (SEQ_SHOW_STRIP_SOURCE)) && source[0] != '\0'; + bool show_duration = sseq->flag & SEQ_SHOW_STRIP_DURATION; + + size_t string_len = 0; + if (show_name) { + string_len = BLI_snprintf(r_overlay_string, overlay_string_len, "%s", name); + if (show_source || show_duration) { + string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, " | "); } - else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + } + if (show_source) { + string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, "%s", source); + if (show_duration) { + string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, " | "); } } - else if (seq->type == SEQ_TYPE_MOVIE) { - str_len = BLI_snprintf(str, - sizeof(str), - "%s: %s%s | %d", - name, - seq->strip->dir, - seq->strip->stripdata->name, - seq->len); + if (show_duration) { + string_len += BLI_snprintf( + r_overlay_string + string_len, overlay_string_len, "%d", strip_duration); } - else { - /* Should never get here!, but might with files from future. */ - BLI_assert(0); + return string_len; +} + +/* Draw info text on a sequence strip. */ +static void draw_seq_text_overlay(View2D *v2d, + Sequence *seq, + SpaceSeq *sseq, + float x1, + float x2, + float y1, + float y2, + bool seq_active) +{ + char overlay_string[FILE_MAX]; + size_t overlay_string_len = draw_seq_text_get_overlay_string( + sseq, seq, overlay_string, sizeof(overlay_string)); - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + if (overlay_string_len == 0) { + return; } /* White text for the active strip. */ + uchar col[4]; col[0] = col[1] = col[2] = seq_active ? 255 : 10; col[3] = 255; @@ -731,15 +729,16 @@ static void draw_seq_text(View2D *v2d, } } + rctf rect; rect.xmin = x1; rect.ymin = y1; rect.xmax = x2; rect.ymax = y2; - UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col); + UI_view2d_text_cache_add_rectf(v2d, &rect, overlay_string, overlay_string_len, col); } -static void draw_sequence_extensions(Scene *scene, Sequence *seq, uint pos, float pixely) +static void draw_sequence_extensions_overlay(Scene *scene, Sequence *seq, uint pos, float pixely) { float x1, x2, y1, y2; uchar col[4], blend_col[3]; @@ -850,9 +849,9 @@ static void draw_seq_background(Scene *scene, /* Draw the main strip body. */ if (is_single_image) { immRectf(pos, - BKE_sequence_tx_get_final_left(seq, false), + SEQ_transform_get_left_handle_frame(seq, false), y1, - BKE_sequence_tx_get_final_right(seq, false), + SEQ_transform_get_right_handle_frame(seq, false), y2); } else { @@ -988,7 +987,7 @@ static void fcurve_batch_add_verts(GPUVertBuf *vbo, * - Volume for sound strips. * - Opacity for the other types. */ -static void draw_seq_fcurve( +static void draw_seq_fcurve_overlay( Scene *scene, View2D *v2d, Sequence *seq, float x1, float y1, float x2, float y2, float pixelx) { FCurve *fcu; @@ -1077,7 +1076,7 @@ static void draw_seq_strip(const bContext *C, float pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); /* Check if we are doing "solo preview". */ - bool is_single_image = (char)BKE_sequence_single_check(seq); + bool is_single_image = (char)SEQ_transform_single_image_check(seq); /* Draw strip body. */ x1 = (seq->startstill) ? seq->start : seq->startdisp; @@ -1085,11 +1084,21 @@ static void draw_seq_strip(const bContext *C, x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp; y2 = seq->machine + SEQ_STRIP_OFSTOP; - /* Calculate height needed for drawing text on strip. */ - float text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely); + float text_margin_y; + bool y_threshold; + if ((sseq->flag & SEQ_SHOW_STRIP_NAME) || (sseq->flag & SEQ_SHOW_STRIP_SOURCE) || + (sseq->flag & SEQ_SHOW_STRIP_DURATION)) { - /* Is there enough space for drawing something else than text? */ - bool y_threshold = ((y2 - y1) / pixely) > 20 * U.dpi_fac; + /* Calculate height needed for drawing text on strip. */ + text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely); + + /* Is there enough space for drawing something else than text? */ + y_threshold = ((y2 - y1) / pixely) > 20 * U.dpi_fac; + } + else { + text_margin_y = y2; + y_threshold = 1; + } uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -1102,12 +1111,13 @@ static void draw_seq_strip(const bContext *C, } /* Draw strip offsets when flag is enabled or during "solo preview". */ - if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) { - if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) { - draw_sequence_extensions(scene, seq, pos, pixely); + if ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) { + if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) { + if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) { + draw_sequence_extensions_overlay(scene, seq, pos, pixely); + } } } - immUnbindProgram(); x1 = seq->startdisp; @@ -1118,31 +1128,31 @@ static void draw_seq_strip(const bContext *C, drawmeta_contents(scene, seq, x1, y1, x2, y2); } - if (sseq->flag & SEQ_SHOW_FCURVES) { - draw_seq_fcurve(scene, v2d, seq, x1, y1, x2, y2, pixelx); + if ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY) && (sseq->flag & SEQ_SHOW_FCURVES)) { + draw_seq_fcurve_overlay(scene, v2d, seq, x1, y1, x2, y2, pixelx); } /* Draw sound strip waveform. */ - if ((seq->type == SEQ_TYPE_SOUND_RAM) && (sseq->flag & SEQ_NO_WAVEFORMS) == 0) { - draw_seq_waveform(v2d, - C, - sseq, - scene, - seq, - x1, - y_threshold ? y1 + 0.05f : y1, - x2, - y_threshold ? text_margin_y : y2, - BLI_rctf_size_x(®ion->v2d.cur) / region->winx); + if ((seq->type == SEQ_TYPE_SOUND_RAM) && ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) && + (sseq->flag & SEQ_NO_WAVEFORMS) == 0) { + draw_seq_waveform_overlay(v2d, + C, + sseq, + scene, + seq, + x1, + y_threshold ? y1 + 0.05f : y1, + x2, + y_threshold ? text_margin_y : y2, + BLI_rctf_size_x(®ion->v2d.cur) / region->winx); } - /* Draw locked state. */ if (seq->flag & SEQ_LOCK) { draw_seq_locked(x1, y1, x2, y2); } /* Draw Red line on the top of invalid strip (Missing media). */ - if (!BKE_sequence_is_valid_check(seq)) { + if (!SEQ_sequence_has_source(seq)) { draw_seq_invalid(x1, x2, y2, text_margin_y); } @@ -1162,11 +1172,21 @@ static void draw_seq_strip(const bContext *C, calculate_seq_text_offsets(v2d, seq, &x1, &x2, pixelx); - /* Don't draw strip if there is not enough vertical or horizontal space. */ - if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) { - /* Depending on the vertical space, draw text on top or in the center of strip. */ - draw_seq_text( - v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active, y_threshold); + /* If a waveform is drawn, avoid drawing text when there is not enough vertical space. */ + if (seq->type == SEQ_TYPE_SOUND_RAM) { + if (!y_threshold && (sseq->flag & SEQ_NO_WAVEFORMS) == 0 && + ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) { + return; + } + } + + if (sseq->flag & SEQ_SHOW_STRIP_OVERLAY) { + /* Don't draw strip if there is not enough vertical or horizontal space. */ + if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) { + /* Depending on the vertical space, draw text on top or in the center of strip. */ + draw_seq_text_overlay( + v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active); + } } } @@ -1360,7 +1380,7 @@ static void sequencer_display_size(Scene *scene, float r_viewrect[2]) r_viewrect[0] *= scene->r.xasp / scene->r.yasp; } -static void sequencer_draw_gpencil(const bContext *C) +static void sequencer_draw_gpencil_overlay(const bContext *C) { /* Draw grease-pencil (image aligned). */ ED_annotation_draw_2dimage(C); @@ -1373,7 +1393,9 @@ static void sequencer_draw_gpencil(const bContext *C) } /* Draw content and safety borders borders. */ -static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, const Scene *scene) +static void sequencer_draw_borders_overlay(const SpaceSeq *sseq, + const View2D *v2d, + const Scene *scene) { float x1 = v2d->tot.xmin; float y1 = v2d->tot.ymin; @@ -1428,7 +1450,7 @@ void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *region, S // if (sc->mode == SC_MODE_MASKEDIT) if (0 && sseq->mainb == SEQ_DRAW_IMG_IMBUF) { - Mask *mask = BKE_sequencer_mask_get(scene); + Mask *mask = SEQ_active_mask_get(scene); if (mask) { int width, height; @@ -1460,7 +1482,7 @@ void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *region, S /* Force redraw, when prefetching and using cache view. */ static void seq_prefetch_wm_notify(const bContext *C, Scene *scene) { - if (BKE_sequencer_prefetch_need_redraw(CTX_data_main(C), scene)) { + if (SEQ_prefetch_need_redraw(CTX_data_main(C), scene)) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL); } } @@ -1825,17 +1847,17 @@ void sequencer_draw_preview(const bContext *C, C, scene, region, sseq, ibuf, scope, draw_overlay, draw_backdrop); /* Draw over image. */ - if (sseq->flag & SEQ_SHOW_METADATA) { + if (sseq->flag & SEQ_SHOW_METADATA && sseq->flag & SEQ_SHOW_STRIP_OVERLAY) { ED_region_image_metadata_draw(0.0, 0.0, ibuf, &v2d->tot, 1.0, 1.0); } } - if (show_imbuf) { - sequencer_draw_borders(sseq, v2d, scene); + if (show_imbuf && (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) { + sequencer_draw_borders_overlay(sseq, v2d, scene); } - if (draw_gpencil && show_imbuf) { - sequencer_draw_gpencil(C); + if (draw_gpencil && show_imbuf && (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) { + sequencer_draw_gpencil_overlay(C); } #if 0 sequencer_draw_maskedit(C, scene, region, sseq); @@ -1900,7 +1922,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) Scene *scene = CTX_data_scene(C); View2D *v2d = ®ion->v2d; SpaceSeq *sseq = CTX_wm_space_seq(C); - Sequence *last_seq = BKE_sequencer_active_get(scene); + Sequence *last_seq = SEQ_select_active_get(scene); int sel = 0, j; float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); @@ -1943,7 +1965,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) draw_seq_strip(C, sseq, scene, region, last_seq, pixelx, true); /* When active strip is an effect, highlight its inputs. */ - if (BKE_sequence_effect_get_num_inputs(last_seq->type) > 0) { + if (SEQ_effect_get_num_inputs(last_seq->type) > 0) { draw_effect_inputs_highlight(last_seq); } /* When active is a Multi-cam strip, highlight its source channel. */ @@ -1987,7 +2009,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) static void seq_draw_sfra_efra(Scene *scene, View2D *v2d) { - const Editing *ed = BKE_sequencer_editing_get(scene, false); + const Editing *ed = SEQ_editing_get(scene, false); const int frame_sta = scene->r.sfra; const int frame_end = scene->r.efra + 1; @@ -2089,8 +2111,10 @@ static bool draw_cache_view_init_fn(void *userdata, size_t item_count) } /* Called as a callback */ -static bool draw_cache_view_iter_fn( - void *userdata, struct Sequence *seq, int timeline_frame, int cache_type, float UNUSED(cost)) +static bool draw_cache_view_iter_fn(void *userdata, + struct Sequence *seq, + int timeline_frame, + int cache_type) { CacheDrawData *drawdata = userdata; struct View2D *v2d = drawdata->v2d; @@ -2252,7 +2276,7 @@ static void draw_cache_view(const bContext *C) userdata.composite_vbo = GPU_vertbuf_create_with_format(&format); userdata.final_out_vbo = GPU_vertbuf_create_with_format(&format); - BKE_sequencer_cache_iterate(scene, &userdata, draw_cache_view_init_fn, draw_cache_view_iter_fn); + SEQ_cache_iterate(scene, &userdata, draw_cache_view_init_fn, draw_cache_view_iter_fn); draw_cache_view_batch(userdata.raw_vbo, userdata.raw_vert_count, 1.0f, 0.1f, 0.02f, 0.4f); draw_cache_view_batch( @@ -2269,7 +2293,7 @@ static void draw_cache_view(const bContext *C) void draw_timeline_seq(const bContext *C, ARegion *region) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); SpaceSeq *sseq = CTX_wm_space_seq(C); View2D *v2d = ®ion->v2d; short cfra_flag = 0; @@ -2292,7 +2316,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region) UI_view2d_view_ortho(v2d); /* Get timeline bound-box, needed for the scroll-bars. */ - boundbox_seq(scene, &v2d->tot); + SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &v2d->tot); draw_seq_backdrop(v2d); UI_view2d_constant_grid_draw(v2d, FPS); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 93b17830c0f..c3553ac88ad 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -45,7 +45,19 @@ #include "BKE_report.h" #include "BKE_sound.h" +#include "SEQ_add.h" +#include "SEQ_clipboard.h" +#include "SEQ_edit.h" +#include "SEQ_effects.h" +#include "SEQ_iterator.h" +#include "SEQ_prefetch.h" +#include "SEQ_relations.h" +#include "SEQ_render.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" +#include "SEQ_utils.h" #include "WM_api.h" #include "WM_types.h" @@ -96,7 +108,7 @@ bool ED_space_sequencer_maskedit_mask_poll(bContext *C) bool ED_space_sequencer_check_show_maskedit(SpaceSeq *sseq, Scene *scene) { if (sseq && sseq->mainb == SEQ_DRAW_IMG_IMBUF) { - return (BKE_sequencer_mask_get(scene) != NULL); + return (SEQ_active_mask_get(scene) != NULL); } return false; @@ -136,14 +148,14 @@ bool ED_space_sequencer_check_show_strip(SpaceSeq *sseq) /* Operator functions. */ bool sequencer_edit_poll(bContext *C) { - return (BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL); + return (SEQ_editing_get(CTX_data_scene(C), false) != NULL); } #if 0 /* UNUSED */ bool sequencer_strip_poll(bContext *C) { Editing *ed; - return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && + return (((ed = SEQ_editing_get(CTX_data_scene(C), false)) != NULL) && (ed->act_seq != NULL)); } #endif @@ -152,14 +164,14 @@ bool sequencer_strip_has_path_poll(bContext *C) { Editing *ed; Sequence *seq; - return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && + return (((ed = SEQ_editing_get(CTX_data_scene(C), false)) != 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 = BKE_sequencer_editing_get(CTX_data_scene(C), false); + Editing *ed = SEQ_editing_get(CTX_data_scene(C), false); if (ed && sseq && (sseq->mainb == SEQ_DRAW_IMG_IMBUF)) { return 1; } @@ -183,117 +195,13 @@ bool sequencer_view_strips_poll(bContext *C) /** \name Remove Gaps Operator * \{ */ -static bool sequence_offset_after_frame(Scene *scene, const int delta, const int timeline_frame) -{ - Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); - bool done = false; - TimeMarker *marker; - - /* All strips >= timeline_frame are shifted. */ - - if (ed == NULL) { - return 0; - } - - for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if (seq->startdisp >= timeline_frame) { - BKE_sequence_translate(scene, seq, delta); - BKE_sequence_calc(scene, seq); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); - done = true; - } - } - - if (!scene->toolsettings->lock_markers) { - for (marker = scene->markers.first; marker; marker = marker->next) { - if (marker->frame >= timeline_frame) { - marker->frame += delta; - } - } - } - - return done; -} - -void boundbox_seq(Scene *scene, rctf *rect) -{ - Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); - float min[2], max[2]; - - if (ed == NULL) { - return; - } - - min[0] = SFRA; - max[0] = EFRA + 1; - min[1] = 0.0; - max[1] = 8.0; - - seq = ed->seqbasep->first; - while (seq) { - - if (min[0] > seq->startdisp - 1) { - min[0] = seq->startdisp - 1; - } - if (max[0] < seq->enddisp + 1) { - max[0] = seq->enddisp + 1; - } - if (max[1] < seq->machine + 2) { - max[1] = seq->machine + 2; - } - - seq = seq->next; - } - - rect->xmin = min[0]; - rect->xmax = max[0]; - rect->ymin = min[1]; - rect->ymax = max[1]; -} - static int sequencer_gap_remove_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - rctf rectf; - int timeline_frame, efra, sfra; - bool first = false, done; - bool do_all = RNA_boolean_get(op->ptr, "all"); - - /* Get first and last frame. */ - boundbox_seq(scene, &rectf); - sfra = (int)rectf.xmin; - efra = (int)rectf.xmax; - - /* Check if the current frame has a gap already. */ - for (timeline_frame = CFRA; timeline_frame >= sfra; timeline_frame--) { - if (SEQ_render_evaluate_frame(scene, timeline_frame)) { - first = true; - break; - } - } + const bool do_all = RNA_boolean_get(op->ptr, "all"); + const Editing *ed = SEQ_editing_get(scene, false); - for (; timeline_frame < efra; timeline_frame++) { - /* There's still no strip to remove a gap for. */ - if (first == false) { - if (SEQ_render_evaluate_frame(scene, timeline_frame)) { - first = true; - } - } - else if (SEQ_render_evaluate_frame(scene, timeline_frame) == 0) { - done = true; - while (SEQ_render_evaluate_frame(scene, timeline_frame) == 0) { - done = sequence_offset_after_frame(scene, -1, timeline_frame); - if (done == false) { - break; - } - } - if (done == false || do_all == false) { - break; - } - } - } + SEQ_edit_remove_gaps(scene, ed->seqbasep, CFRA, do_all); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -330,9 +238,9 @@ void SEQUENCER_OT_gap_remove(struct wmOperatorType *ot) static int sequencer_gap_insert_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - int frames = RNA_int_get(op->ptr, "frames"); - - sequence_offset_after_frame(scene, frames, CFRA); + const int frames = RNA_int_get(op->ptr, "frames"); + const Editing *ed = SEQ_editing_get(scene, false); + SEQ_transform_offset_after_frame(scene, ed->seqbasep, frames, CFRA); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -377,7 +285,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; int snap_frame; @@ -386,22 +294,22 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) /* Check metas. */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK) && - BKE_sequence_tx_test(seq)) { + SEQ_transform_sequence_can_be_translated(seq)) { if ((seq->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) == 0) { - BKE_sequence_translate( + SEQ_transform_translate_sequence( scene, seq, (snap_frame - seq->startofs + seq->startstill) - seq->start); } else { if (seq->flag & SEQ_LEFTSEL) { - BKE_sequence_tx_set_final_left(seq, snap_frame); + SEQ_transform_set_left_handle_frame(seq, snap_frame); } else { /* SEQ_RIGHTSEL */ - BKE_sequence_tx_set_final_right(seq, snap_frame); + SEQ_transform_set_right_handle_frame(seq, snap_frame); } - BKE_sequence_tx_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL); - BKE_sequence_single_fix(seq); + SEQ_transform_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL); + SEQ_transform_fix_single_image_seq_offsets(seq); } - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); } } @@ -410,8 +318,8 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK)) { seq->flag &= ~SEQ_OVERLAP; - if (BKE_sequence_test_overlap(ed->seqbasep, seq)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); } } } @@ -420,21 +328,21 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->type & SEQ_TYPE_EFFECT) { if (seq->seq1 && (seq->seq1->flag & SELECT)) { - BKE_sequencer_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); - BKE_sequence_calc(scene, seq); + SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_time_update_sequence(scene, seq); } else if (seq->seq2 && (seq->seq2->flag & SELECT)) { - BKE_sequencer_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); - BKE_sequence_calc(scene, seq); + SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_time_update_sequence(scene, seq); } else if (seq->seq3 && (seq->seq3->flag & SELECT)) { - BKE_sequencer_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); - BKE_sequence_calc(scene, seq); + SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_time_update_sequence(scene, seq); } } } - BKE_sequencer_sort(scene); + SEQ_sort(scene); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -537,7 +445,7 @@ static int slip_add_sequences_recursive( for (seq = seqbasep->first; seq; seq = seq->next) { if (!do_trim || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) { seq_array[offset + num_items] = seq; - trim[offset + num_items] = do_trim; + trim[offset + num_items] = do_trim && ((seq->type & SEQ_TYPE_EFFECT) == 0); num_items++; if (seq->type == SEQ_TYPE_META) { @@ -545,9 +453,6 @@ static int slip_add_sequences_recursive( num_items += slip_add_sequences_recursive( &seq->seqbase, seq_array, trim, num_items + offset, false); } - else if (seq->type & SEQ_TYPE_EFFECT) { - trim[offset + num_items] = false; - } } } @@ -577,7 +482,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve { SlipData *data; Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); float mouseloc[2]; int num_seq; View2D *v2d = UI_view2d_fromcontext(C); @@ -625,7 +530,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); bool changed = false; /* Iterate in reverse so meta-strips are iterated after their children. */ @@ -675,11 +580,11 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset) * we can skip calculating for effects. * This way we can avoid an extra loop just for effects. */ if (!(seq->type & SEQ_TYPE_EFFECT)) { - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); } } if (changed) { - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); } return changed; } @@ -709,7 +614,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); int offset = RNA_int_get(op->ptr, "offset"); bool success = false; @@ -844,7 +749,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even case EVT_ESCKEY: case RIGHTMOUSE: { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); for (int i = 0; i < data->num_seq; i++) { transseq_restore(data->ts + i, data->seq_array[i]); @@ -852,8 +757,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even for (int i = 0; i < data->num_seq; i++) { Sequence *seq = data->seq_array[i]; - BKE_sequence_reload_new_file(bmain, scene, seq, false); - BKE_sequence_calc(scene, seq); + SEQ_add_reload_new_file(bmain, scene, seq, false); + SEQ_time_update_sequence(scene, seq); } MEM_freeN(data->seq_array); @@ -864,7 +769,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); if (area) { ED_area_status_text(area, NULL); @@ -946,7 +851,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; bool selected; @@ -957,13 +862,13 @@ static int sequencer_mute_exec(bContext *C, wmOperator *op) if (selected) { if (seq->flag & SELECT) { seq->flag |= SEQ_MUTE; - BKE_sequence_invalidate_dependent(scene, seq); + SEQ_relations_invalidate_dependent(scene, seq); } } else { if ((seq->flag & SELECT) == 0) { seq->flag |= SEQ_MUTE; - BKE_sequence_invalidate_dependent(scene, seq); + SEQ_relations_invalidate_dependent(scene, seq); } } } @@ -1002,7 +907,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; bool selected; @@ -1013,13 +918,13 @@ static int sequencer_unmute_exec(bContext *C, wmOperator *op) if (selected) { if (seq->flag & SELECT) { seq->flag &= ~SEQ_MUTE; - BKE_sequence_invalidate_dependent(scene, seq); + SEQ_relations_invalidate_dependent(scene, seq); } } else { if ((seq->flag & SELECT) == 0) { seq->flag &= ~SEQ_MUTE; - BKE_sequence_invalidate_dependent(scene, seq); + SEQ_relations_invalidate_dependent(scene, seq); } } } @@ -1058,7 +963,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; for (seq = ed->seqbasep->first; seq; seq = seq->next) { @@ -1096,7 +1001,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; for (seq = ed->seqbasep->first; seq; seq = seq->next) { @@ -1135,18 +1040,18 @@ static int sequencer_reload_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; const bool adjust_length = RNA_boolean_get(op->ptr, "adjust_length"); for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { - BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1); - BKE_sequence_reload_new_file(bmain, scene, seq, !adjust_length); + SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1); + SEQ_add_reload_new_file(bmain, scene, seq, !adjust_length); if (adjust_length) { - if (BKE_sequence_test_overlap(ed->seqbasep, seq)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); } } } @@ -1198,9 +1103,9 @@ 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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1233,18 +1138,18 @@ int seq_effect_find_selected(Scene *scene, Sequence **r_selseq3, const char **r_error_str) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq1 = NULL, *seq2 = NULL, *seq3 = NULL, *seq; *r_error_str = NULL; if (!activeseq) { - seq2 = BKE_sequencer_active_get(scene); + seq2 = SEQ_select_active_get(scene); } for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { - if (seq->type == SEQ_TYPE_SOUND_RAM && BKE_sequence_effect_get_num_inputs(type) != 0) { + if (seq->type == SEQ_TYPE_SOUND_RAM && SEQ_effect_get_num_inputs(type) != 0) { *r_error_str = N_("Cannot apply effects to audio sequence strips"); return 0; } @@ -1274,7 +1179,7 @@ int seq_effect_find_selected(Scene *scene, seq3 = tmp; } - switch (BKE_sequence_effect_get_num_inputs(type)) { + switch (SEQ_effect_get_num_inputs(type)) { case 0: *r_selseq1 = *r_selseq2 = *r_selseq3 = NULL; return 1; /* Success. */ @@ -1311,10 +1216,10 @@ int seq_effect_find_selected(Scene *scene, *r_selseq3 = seq3; /* TODO(Richard): This function needs some refactoring, this is just quick hack for T73828. */ - if (BKE_sequence_effect_get_num_inputs(type) < 3) { + if (SEQ_effect_get_num_inputs(type) < 3) { *r_selseq3 = NULL; } - if (BKE_sequence_effect_get_num_inputs(type) < 2) { + if (SEQ_effect_get_num_inputs(type) < 2) { *r_selseq2 = NULL; } @@ -1324,24 +1229,24 @@ int seq_effect_find_selected(Scene *scene, static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Sequence *seq1, *seq2, *seq3, *last_seq = BKE_sequencer_active_get(scene); + Sequence *seq1, *seq2, *seq3, *last_seq = SEQ_select_active_get(scene); const char *error_msg; - if (BKE_sequence_effect_get_num_inputs(last_seq->type) == 0) { + if (SEQ_effect_get_num_inputs(last_seq->type) == 0) { BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: strip has no inputs"); return OPERATOR_CANCELLED; } if (!seq_effect_find_selected( scene, last_seq, last_seq->type, &seq1, &seq2, &seq3, &error_msg) || - BKE_sequence_effect_get_num_inputs(last_seq->type) == 0) { + SEQ_effect_get_num_inputs(last_seq->type) == 0) { BKE_report(op->reports, RPT_ERROR, error_msg); return OPERATOR_CANCELLED; } /* Check if reassigning would create recursivity. */ - if (BKE_sequencer_render_loop_check(seq1, last_seq) || - BKE_sequencer_render_loop_check(seq2, last_seq) || - BKE_sequencer_render_loop_check(seq3, last_seq)) { + if (SEQ_relations_render_loop_check(seq1, last_seq) || + SEQ_relations_render_loop_check(seq2, last_seq) || + SEQ_relations_render_loop_check(seq3, last_seq)) { BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: recursion detected"); return OPERATOR_CANCELLED; } @@ -1350,7 +1255,7 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op) last_seq->seq2 = seq2; last_seq->seq3 = seq3; - BKE_sequencer_update_changed_seq_and_deps(scene, last_seq, 1, 1); + SEQ_relations_update_changed_seq_and_deps(scene, last_seq, 1, 1); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1360,10 +1265,10 @@ 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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { - Sequence *last_seq = BKE_sequencer_active_get(scene); + Sequence *last_seq = SEQ_select_active_get(scene); if (last_seq && (last_seq->type & SEQ_TYPE_EFFECT)) { return 1; } @@ -1396,7 +1301,7 @@ void SEQUENCER_OT_reassign_inputs(struct wmOperatorType *ot) static int sequencer_swap_inputs_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Sequence *seq, *last_seq = BKE_sequencer_active_get(scene); + Sequence *seq, *last_seq = SEQ_select_active_get(scene); if (last_seq->seq1 == NULL || last_seq->seq2 == NULL) { BKE_report(op->reports, RPT_ERROR, "No valid inputs to swap"); @@ -1407,7 +1312,7 @@ static int sequencer_swap_inputs_exec(bContext *C, wmOperator *op) last_seq->seq1 = last_seq->seq2; last_seq->seq2 = seq; - BKE_sequencer_update_changed_seq_and_deps(scene, last_seq, 1, 1); + SEQ_relations_update_changed_seq_and_deps(scene, last_seq, 1, 1); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1467,7 +1372,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); bool changed = false; bool seq_selected = false; @@ -1478,7 +1383,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) const int split_side = RNA_enum_get(op->ptr, "side"); const bool ignore_selection = RNA_boolean_get(op->ptr, "ignore_selection"); - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); LISTBASE_FOREACH_BACKWARD (Sequence *, seq, ed->seqbasep) { if (use_cursor_position && seq->machine != split_channel) { @@ -1530,7 +1435,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) } } - BKE_sequencer_sort(scene); + SEQ_sort(scene); } if (changed) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1673,15 +1578,15 @@ static int apply_unique_name_fn(Sequence *seq, void *arg_pt) char name[sizeof(seq->name) - 2]; BLI_strncpy_utf8(name, seq->name + 2, sizeof(name)); - BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); - BKE_sequencer_dupe_animdata(scene, name, seq->name + 2); + SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); + SEQ_dupe_animdata(scene, name, seq->name + 2); return 1; } static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); ListBase nseqbase = {NULL, NULL}; @@ -1689,16 +1594,16 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } - BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT, 0); + SEQ_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT, 0); if (nseqbase.first) { Sequence *seq = nseqbase.first; /* Rely on the nseqbase list being added at the end. - * Their UUIDs has been re-generated by the BKE_sequence_base_dupli_recursive(), */ + * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */ BLI_movelisttolist(ed->seqbasep, &nseqbase); for (; seq; seq = seq->next) { - BKE_sequencer_recursive_apply(seq, apply_unique_name_fn, scene); + SEQ_iterator_recursive_apply(seq, apply_unique_name_fn, scene); } WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1733,18 +1638,18 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); SEQ_CURRENT_BEGIN (scene->ed, seq) { if (seq->flag & SELECT) { - BKE_sequencer_flag_for_removal(scene, ed->seqbasep, seq); + SEQ_edit_flag_for_removal(scene, ed->seqbasep, seq); } } SEQ_CURRENT_END; - BKE_sequencer_remove_flagged_sequences(scene, ed->seqbasep); + SEQ_edit_remove_flagged_sequences(scene, ed->seqbasep); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); DEG_relations_tag_update(bmain); @@ -1794,7 +1699,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; /* For effects, try to find a replacement input. */ @@ -1807,14 +1712,14 @@ static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op)) /* Update lengths, etc. */ seq = ed->seqbasep->first; while (seq) { - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); seq = seq->next; } for (seq = ed->seqbasep->first; seq; seq = seq->next) { if ((seq->type & SEQ_TYPE_EFFECT) == 0 && (seq->flag & SELECT)) { - if (BKE_sequence_test_overlap(ed->seqbasep, seq)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); } } } @@ -1849,7 +1754,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq, *seq_new; Strip *strip_new; @@ -1859,7 +1764,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) seq = ed->seqbasep->first; /* Poll checks this is valid. */ - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); while (seq) { if ((seq->flag & SELECT) && (seq->type == SEQ_TYPE_IMAGE) && (seq->len > 1)) { @@ -1871,14 +1776,14 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) /* if (seq->ipo) id_us_min(&seq->ipo->id); */ /* XXX, remove fcurve and assign to split image strips */ - start_ofs = timeline_frame = BKE_sequence_tx_get_final_left(seq, false); - frame_end = BKE_sequence_tx_get_final_right(seq, false); + start_ofs = timeline_frame = SEQ_transform_get_left_handle_frame(seq, false); + frame_end = SEQ_transform_get_right_handle_frame(seq, false); while (timeline_frame < frame_end) { /* New seq. */ se = SEQ_render_give_stripelem(seq, timeline_frame); - seq_new = BKE_sequence_dupli_recursive( + seq_new = SEQ_sequence_dupli_recursive( scene, scene, ed->seqbasep, seq, SEQ_DUPE_UNIQUE_NAME); seq_new->start = start_ofs; @@ -1897,12 +1802,12 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) BLI_strncpy(se_new->name, se->name, sizeof(se_new->name)); strip_new->stripdata = se_new; - BKE_sequence_calc(scene, seq_new); + SEQ_time_update_sequence(scene, seq_new); if (step > 1) { seq_new->flag &= ~SEQ_OVERLAP; - if (BKE_sequence_test_overlap(ed->seqbasep, seq_new)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq_new, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq_new)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq_new, scene); } } @@ -1913,7 +1818,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) } seq_next = seq->next; - BKE_sequence_free(scene, seq, true); + SEQ_sequence_free(scene, seq, true); seq = seq_next; } else { @@ -1921,7 +1826,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) } } - BKE_sequencer_sort(scene); + SEQ_sort(scene); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1980,8 +1885,8 @@ void recurs_sel_seq(Sequence *seqm) static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *last_seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *last_seq = SEQ_select_active_get(scene); MetaStack *ms; if (last_seq && last_seq->type == SEQ_TYPE_META && last_seq->flag & SELECT) { @@ -1994,7 +1899,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) ed->seqbasep = &last_seq->seqbase; - BKE_sequencer_active_set(scene, NULL); + SEQ_select_active_set(scene, NULL); } else { /* Exit metastrip if possible. */ @@ -2017,23 +1922,23 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* Recalc all: the meta can have effects connected to it. */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); } /* 2.73+, keeping endpoints is important! * Moving them around means you can't usefully use metas in a complex edit. */ #if 1 - BKE_sequence_tx_set_final_left(ms->parseq, ms->disp_range[0]); - BKE_sequence_tx_set_final_right(ms->parseq, ms->disp_range[1]); - BKE_sequence_single_fix(ms->parseq); - BKE_sequence_calc(scene, ms->parseq); + SEQ_transform_set_left_handle_frame(ms->parseq, ms->disp_range[0]); + SEQ_transform_set_right_handle_frame(ms->parseq, ms->disp_range[1]); + SEQ_transform_fix_single_image_seq_offsets(ms->parseq); + SEQ_time_update_sequence(scene, ms->parseq); #else - if (BKE_sequence_test_overlap(ed->seqbasep, ms->parseq)) { - BKE_sequence_base_shuffle(ed->seqbasep, ms->parseq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, ms->parseq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, ms->parseq, scene); } #endif - BKE_sequencer_active_set(scene, ms->parseq); + SEQ_select_active_set(scene, ms->parseq); ms->parseq->flag |= SELECT; recurs_sel_seq(ms->parseq); @@ -2071,21 +1976,21 @@ 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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); - Sequence *seq, *seqm, *next, *last_seq = BKE_sequencer_active_get(scene); + Sequence *seq, *seqm, *next, *last_seq = SEQ_select_active_get(scene); int channel_max = 1; - if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) { + if (SEQ_transform_seqbase_isolated_sel_check(ed->seqbasep) == false) { BKE_report(op->reports, RPT_ERROR, "Please select all related strips"); return OPERATOR_CANCELLED; } - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); /* Remove all selected from main list, and put in meta. */ - seqm = BKE_sequence_alloc(ed->seqbasep, 1, 1, SEQ_TYPE_META); /* Channel number set later. */ + seqm = SEQ_sequence_alloc(ed->seqbasep, 1, 1, SEQ_TYPE_META); /* Channel number set later. */ strcpy(seqm->name + 2, "MetaStrip"); seqm->flag = SELECT; @@ -2093,7 +1998,7 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op) while (seq) { next = seq->next; if (seq != seqm && (seq->flag & SELECT)) { - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); channel_max = max_ii(seq->machine, channel_max); /* Sequence is moved within the same edit, no need to re-generate the UUID. */ BLI_remlink(ed->seqbasep, seq); @@ -2102,18 +2007,18 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op) seq = next; } seqm->machine = last_seq ? last_seq->machine : channel_max; - BKE_sequence_calc(scene, seqm); + SEQ_time_update_sequence(scene, seqm); - BKE_sequencer_active_set(scene, seqm); + SEQ_select_active_set(scene, seqm); - if (BKE_sequence_test_overlap(ed->seqbasep, seqm)) { - BKE_sequence_base_shuffle(ed->seqbasep, seqm, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seqm)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seqm, scene); } DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); - BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqm); - BKE_sequence_invalidate_cache_composite(scene, seqm); + SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqm); + SEQ_relations_invalidate_cache_composite(scene, seqm); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -2160,7 +2065,7 @@ static int seq_depends_on_meta(Sequence *seq, Sequence *seqm) static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short deleteall) { Sequence *seq, *seqn; - Sequence *last_seq = BKE_sequencer_active_get(scene); + Sequence *last_seq = SEQ_select_active_get(scene); seq = lb->first; while (seq) { @@ -2168,12 +2073,12 @@ static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short de if ((seq->flag & flag) || deleteall) { BLI_remlink(lb, seq); if (seq == last_seq) { - BKE_sequencer_active_set(scene, NULL); + SEQ_select_active_set(scene, NULL); } if (seq->type == SEQ_TYPE_META) { recurs_del_seq_flag(scene, &seq->seqbase, flag, 1); } - BKE_sequence_free(scene, seq, true); + SEQ_sequence_free(scene, seq, true); } seq = seqn; } @@ -2182,18 +2087,18 @@ static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short de static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); - Sequence *seq, *last_seq = BKE_sequencer_active_get(scene); /* last_seq checks (ed == NULL) */ + Sequence *seq, *last_seq = SEQ_select_active_get(scene); /* last_seq checks (ed == NULL) */ if (last_seq == NULL || last_seq->type != SEQ_TYPE_META) { return OPERATOR_CANCELLED; } - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); for (seq = last_seq->seqbase.first; seq != NULL; seq = seq->next) { - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); } /* This moves strips from meta to parent, sating within same edit and no new strips are @@ -2204,7 +2109,7 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op)) BLI_listbase_clear(&last_seq->seqbase); BLI_remlink(ed->seqbasep, last_seq); - BKE_sequence_free(scene, last_seq, true); + SEQ_sequence_free(scene, last_seq, true); /* Empty meta strip, delete all effects depending on it. */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { @@ -2220,13 +2125,13 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op)) for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { seq->flag &= ~SEQ_OVERLAP; - if (BKE_sequence_test_overlap(ed->seqbasep, seq)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); } } } - BKE_sequencer_sort(scene); + SEQ_sort(scene); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2262,7 +2167,7 @@ static bool strip_jump_internal(Scene *scene, { bool changed = false; int timeline_frame = CFRA; - int next_frame = BKE_sequencer_find_next_prev_edit( + int next_frame = SEQ_time_find_next_prev_edit( scene, timeline_frame, side, do_skip_mute, do_center, false); if (next_frame != timeline_frame) { @@ -2337,19 +2242,19 @@ static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb) int seq_b_start; seq_b_start = (seqb->start - seqb->startdisp) + seqa->startdisp; - BKE_sequence_translate(scene, seqb, seq_b_start - seqb->start); - BKE_sequence_calc(scene, seqb); + SEQ_transform_translate_sequence(scene, seqb, seq_b_start - seqb->start); + SEQ_time_update_sequence(scene, seqb); seq_a_start = (seqa->start - seqa->startdisp) + seqb->enddisp + gap; - BKE_sequence_translate(scene, seqa, seq_a_start - seqa->start); - BKE_sequence_calc(scene, seqa); + SEQ_transform_translate_sequence(scene, seqa, seq_a_start - seqa->start); + SEQ_time_update_sequence(scene, seqa); } static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel) { /* sel: 0==unselected, 1==selected, -1==don't care. */ Sequence *seq, *best_seq = NULL; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); int dist, best_dist; best_dist = MAXFRAME * 2; @@ -2399,8 +2304,8 @@ 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 = BKE_sequencer_editing_get(scene, false); - Sequence *active_seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *active_seq = SEQ_select_active_get(scene); Sequence *seq, *iseq; int side = RNA_enum_get(op->ptr, "side"); @@ -2413,11 +2318,11 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op) if (seq) { /* Disallow effect strips. */ - if (BKE_sequence_effect_get_num_inputs(seq->type) >= 1 && + if (SEQ_effect_get_num_inputs(seq->type) >= 1 && (seq->effectdata || seq->seq1 || seq->seq2 || seq->seq3)) { return OPERATOR_CANCELLED; } - if ((BKE_sequence_effect_get_num_inputs(active_seq->type) >= 1) && + if ((SEQ_effect_get_num_inputs(active_seq->type) >= 1) && (active_seq->effectdata || active_seq->seq1 || active_seq->seq2 || active_seq->seq3)) { return OPERATOR_CANCELLED; } @@ -2435,7 +2340,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op) for (iseq = scene->ed->seqbasep->first; iseq; iseq = iseq->next) { if ((iseq->type & SEQ_TYPE_EFFECT) && (seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) { - BKE_sequence_calc(scene, iseq); + SEQ_time_update_sequence(scene, iseq); } } @@ -2444,13 +2349,13 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op) if ((iseq->type & SEQ_TYPE_EFFECT) && (seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) { /* This may now overlap. */ - if (BKE_sequence_test_overlap(ed->seqbasep, iseq)) { - BKE_sequence_base_shuffle(ed->seqbasep, iseq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, iseq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, iseq, scene); } } } - BKE_sequencer_sort(scene); + SEQ_sort(scene); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2489,7 +2394,7 @@ static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op)) { int retval = OPERATOR_CANCELLED; Scene *scene = CTX_data_scene(C); - Sequence *active_seq = BKE_sequencer_active_get(scene); + Sequence *active_seq = SEQ_select_active_get(scene); StripElem *se = NULL; if (active_seq == NULL) { @@ -2565,11 +2470,11 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); - BKE_sequencer_free_clipboard(); + SEQ_clipboard_free(); - if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) { + if (SEQ_transform_seqbase_isolated_sel_check(ed->seqbasep) == false) { BKE_report(op->reports, RPT_ERROR, "Please select all related strips"); return OPERATOR_CANCELLED; } @@ -2577,7 +2482,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) /* NOTE: The UUID is re-generated on paste, so we can keep UUID in the clipboard since * nobody can reach them anyway. * This reduces chance or running out of UUIDs if a cat falls asleep on Ctrl-C. */ - BKE_sequence_base_dupli_recursive(scene, + SEQ_sequence_base_dupli_recursive(scene, scene, &seqbase_clipboard, ed->seqbasep, @@ -2593,7 +2498,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) /* Replace datablock pointers with copies, to keep things working in case * data-blocks get deleted or another .blend file is opened. */ - BKE_sequencer_base_clipboard_pointers_store(bmain, &seqbase_clipboard); + SEQ_clipboard_pointers_store(bmain, &seqbase_clipboard); return OPERATOR_FINISHED; } @@ -2622,7 +2527,7 @@ void SEQUENCER_OT_copy(wmOperatorType *ot) void ED_sequencer_deselect_all(Scene *scene) { Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return; @@ -2634,40 +2539,57 @@ void ED_sequencer_deselect_all(Scene *scene) SEQ_CURRENT_END; } -static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) +static int sequencer_paste_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); /* Create if needed. */ + Editing *ed = SEQ_editing_get(scene, true); /* Create if needed. */ ListBase nseqbase = {NULL, NULL}; int ofs; Sequence *iseq, *iseq_first; + if (BLI_listbase_count(&seqbase_clipboard) == 0) { + BKE_report(op->reports, RPT_INFO, "No strips to paste"); + return OPERATOR_CANCELLED; + } + ED_sequencer_deselect_all(scene); - ofs = scene->r.cfra - seqbase_clipboard_frame; + if (RNA_boolean_get(op->ptr, "keep_offset")) { + ofs = scene->r.cfra - seqbase_clipboard_frame; + } + else { + int min_seq_startdisp = INT_MAX; + LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) { + if (seq->startdisp < min_seq_startdisp) { + min_seq_startdisp = seq->startdisp; + } + } + /* Paste strips after playhead. */ + ofs = scene->r.cfra - min_seq_startdisp; + } /* Copy strips, temporarily restoring pointers to actual data-blocks. This * must happen on the clipboard itself, so that copying does user counting * on the actual data-blocks. */ - BKE_sequencer_base_clipboard_pointers_restore(&seqbase_clipboard, bmain); - BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, 0, 0); - BKE_sequencer_base_clipboard_pointers_store(bmain, &seqbase_clipboard); + SEQ_clipboard_pointers_restore(&seqbase_clipboard, bmain); + SEQ_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, 0, 0); + SEQ_clipboard_pointers_store(bmain, &seqbase_clipboard); iseq_first = nseqbase.first; - /* NOTE: BKE_sequence_base_dupli_recursive() takes care of generating new UUIDs for sequences + /* NOTE: SEQ_sequence_base_dupli_recursive() takes care of generating new UUIDs for sequences * in the new list. */ BLI_movelisttolist(ed->seqbasep, &nseqbase); for (iseq = iseq_first; iseq; iseq = iseq->next) { /* Make sure, that pasted strips have unique names. */ - BKE_sequencer_recursive_apply(iseq, apply_unique_name_fn, scene); + SEQ_iterator_recursive_apply(iseq, apply_unique_name_fn, scene); /* Translate after name has been changed, otherwise this will affect animdata of original * strip. */ - BKE_sequence_translate(scene, iseq, ofs); + SEQ_transform_translate_sequence(scene, iseq, ofs); /* Ensure, that pasted strips don't overlap. */ - if (BKE_sequence_test_overlap(ed->seqbasep, iseq)) { - BKE_sequence_base_shuffle(ed->seqbasep, iseq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, iseq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, iseq, scene); } } @@ -2692,6 +2614,11 @@ void SEQUENCER_OT_paste(wmOperatorType *ot) /* Flags. */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Properties. */ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "keep_offset", false, "Keep Offset", "Keep strip offset to playhead when pasting"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ @@ -2707,12 +2634,12 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op) Sequence *seq_other; const char *error_msg; - if (BKE_sequencer_active_get_pair(scene, &seq_act, &seq_other) == 0) { + if (SEQ_select_active_get_pair(scene, &seq_act, &seq_other) == 0) { BKE_report(op->reports, RPT_ERROR, "Please select two strips"); return OPERATOR_CANCELLED; } - if (BKE_sequence_swap(seq_act, seq_other, &error_msg) == 0) { + if (SEQ_edit_sequence_swap(seq_act, seq_other, &error_msg) == 0) { BKE_report(op->reports, RPT_ERROR, error_msg); return OPERATOR_CANCELLED; } @@ -2728,8 +2655,8 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op) seq_act->scene_sound = NULL; seq_other->scene_sound = NULL; - BKE_sequence_calc(scene, seq_act); - BKE_sequence_calc(scene, seq_other); + SEQ_time_update_sequence(scene, seq_act); + SEQ_time_update_sequence(scene, seq_other); if (seq_act->sound) { BKE_sound_add_scene_sound_defaults(scene, seq_act); @@ -2738,8 +2665,8 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op) BKE_sound_add_scene_sound_defaults(scene, seq_other); } - BKE_sequence_invalidate_cache_raw(scene, seq_act); - BKE_sequence_invalidate_cache_raw(scene, seq_other); + SEQ_relations_invalidate_cache_raw(scene, seq_act); + SEQ_relations_invalidate_cache_raw(scene, seq_other); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2777,8 +2704,8 @@ 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 = BKE_sequencer_editing_get(scene, false); - Sequence *seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *seq = SEQ_select_active_get(scene); Sequence **seq_1, **seq_2; @@ -2804,10 +2731,10 @@ static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op) SWAP(Sequence *, *seq_1, *seq_2); - BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1); + SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1); /* Invalidate cache. */ - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -2861,8 +2788,8 @@ EnumPropertyItem sequencer_prop_effect_types[] = { static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *seq = SEQ_select_active_get(scene); const int new_type = RNA_enum_get(op->ptr, "type"); /* Free previous effect and init new effect. */ @@ -2874,23 +2801,22 @@ static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op) /* Can someone explain the logic behind only allowing to increase this, * copied from 2.4x - campbell */ - if (BKE_sequence_effect_get_num_inputs(seq->type) < - BKE_sequence_effect_get_num_inputs(new_type)) { + if (SEQ_effect_get_num_inputs(seq->type) < SEQ_effect_get_num_inputs(new_type)) { BKE_report(op->reports, RPT_ERROR, "New effect needs more input strips"); return OPERATOR_CANCELLED; } - sh = BKE_sequence_get_effect(seq); + sh = SEQ_effect_handle_get(seq); sh.free(seq, true); seq->type = new_type; - sh = BKE_sequence_get_effect(seq); + sh = SEQ_effect_handle_get(seq); sh.init(seq); - BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1); + SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1); /* Invalidate cache. */ - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2928,8 +2854,8 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + 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"); int minext_frameme, numdigits; @@ -2982,12 +2908,12 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) /* Correct start/end frames so we don't move. * Important not to set seq->len = len; allow the function to handle it. */ - BKE_sequence_reload_new_file(bmain, scene, seq, true); + SEQ_add_reload_new_file(bmain, scene, seq, true); - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); /* Invalidate cache. */ - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); } else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { bSound *sound = seq->sound; @@ -3021,7 +2947,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = CTX_data_scene(C); - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); char filepath[FILE_MAX]; BLI_join_dirfile(filepath, sizeof(filepath), seq->strip->dir, seq->strip->stripdata->name); @@ -3105,7 +3031,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Sequence *seq, *seq_next; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); ListBase text_seq = {0}; int iter = 0; FILE *file; @@ -3144,7 +3070,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BLI_listbase_sort(&text_seq, BKE_sequencer_cmp_time_startdisp); + BLI_listbase_sort(&text_seq, SEQ_time_cmp_time_startdisp); /* Open and write file. */ file = BLI_fopen(filepath, "w"); @@ -3183,7 +3109,7 @@ static bool sequencer_strip_is_text_poll(bContext *C) { Editing *ed; Sequence *seq; - return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && + return (((ed = SEQ_editing_get(CTX_data_scene(C), false)) != NULL) && ((seq = ed->act_seq) != NULL) && (seq->type == SEQ_TYPE_TEXT)); } @@ -3220,7 +3146,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; int sfra = MAXFRAME; @@ -3291,7 +3217,7 @@ void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot) static void set_filter_seq(Scene *scene) { Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return; @@ -3305,8 +3231,8 @@ static void set_filter_seq(Scene *scene) if (seq->flag & SELECT) { if (seq->type == SEQ_TYPE_MOVIE) { seq->flag |= SEQ_FILTERY; - BKE_sequence_reload_new_file(bmain, scene, seq, false); - BKE_sequence_calc(scene, seq); + SEQ_add_reload_new_file(bmain, scene, seq, false); + SEQ_time_update_sequence(scene, seq); } } } @@ -3315,8 +3241,8 @@ static void set_filter_seq(Scene *scene) static void UNUSED_FUNCTION(seq_remap_paths)(Scene *scene) { - Sequence *seq, *last_seq = BKE_sequencer_active_get(scene); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Sequence *seq, *last_seq = SEQ_select_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); char from[FILE_MAX], to[FILE_MAX], stripped[FILE_MAX]; if (last_seq == NULL) { @@ -3355,7 +3281,7 @@ static void UNUSED_FUNCTION(seq_remap_paths)(Scene *scene) static Sequence *sequence_find_parent(Scene *scene, Sequence *child) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *parent = NULL; Sequence *seq; @@ -3407,7 +3333,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return NULL; @@ -3441,7 +3367,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); float x, y; float pixelx; float handsize; @@ -3463,7 +3389,7 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[ /* Check for both normal strips, and strips that have been flipped horizontally. */ if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) || ((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x))) { - if (BKE_sequence_tx_test(seq)) { + if (SEQ_transform_sequence_can_be_translated(seq)) { /* Clamp handles to defined size in pixel space. */ handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx); @@ -3499,3 +3425,148 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[ } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Strip Transform Operator + * \{ */ + +enum { + STRIP_TRANSFORM_POSITION, + STRIP_TRANSFORM_SCALE, + STRIP_TRANSFORM_ROTATION, + STRIP_TRANSFORM_ALL, +}; + +static const EnumPropertyItem transform_reset_properties[] = { + {STRIP_TRANSFORM_POSITION, "POSITION", 0, "Position", "Reset strip transform location"}, + {STRIP_TRANSFORM_SCALE, "SCALE", 0, "Scale", "Reset strip transform scale"}, + {STRIP_TRANSFORM_ROTATION, "ROTATION", 0, "Rotation", "Reset strip transform rotation"}, + {STRIP_TRANSFORM_ALL, "ALL", 0, "All", "Reset strip transform location, scale and rotation"}, + {0, NULL, 0, NULL, NULL}, +}; + +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); + Sequence *seq; + const int property = RNA_enum_get(op->ptr, "property"); + + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + if (seq->flag & SELECT && seq->type != SEQ_TYPE_SOUND_RAM) { + StripTransform *transform = seq->strip->transform; + switch (property) { + case STRIP_TRANSFORM_POSITION: + transform->xofs = 0; + transform->yofs = 0; + break; + case STRIP_TRANSFORM_SCALE: + transform->scale_x = 1.0f; + transform->scale_y = 1.0f; + break; + case STRIP_TRANSFORM_ROTATION: + transform->rotation = 0.0f; + break; + case STRIP_TRANSFORM_ALL: + transform->xofs = 0; + transform->yofs = 0; + transform->scale_x = 1.0f; + transform->scale_y = 1.0f; + transform->rotation = 0.0f; + break; + } + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + } + } + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_strip_transform_clear(struct wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Clear Strip Transform"; + ot->idname = "SEQUENCER_OT_strip_transform_clear"; + ot->description = "Reset image transformation to default value"; + + /* Api callbacks. */ + ot->exec = sequencer_strip_transform_clear_exec; + ot->poll = sequencer_edit_poll; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, + "property", + transform_reset_properties, + STRIP_TRANSFORM_ALL, + "Property", + "Strip transform property to be reset"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform Set Fit Operator + * \{ */ + +static const EnumPropertyItem scale_fit_methods[] = { + {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image so fits in preview"}, + {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image so it fills preview completely"}, + {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image so it fills preview"}, + {0, NULL, 0, NULL, NULL}, +}; + +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); + Sequence *seq; + const eSeqImageFitMethod fit_method = RNA_enum_get(op->ptr, "fit_method"); + + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + if (seq->flag & SELECT && seq->type != SEQ_TYPE_SOUND_RAM) { + const int timeline_frame = CFRA; + StripElem *strip_elem = SEQ_render_give_stripelem(seq, timeline_frame); + + if (strip_elem == NULL) { + continue; + } + + SEQ_set_scale_to_fit(seq, + strip_elem->orig_width, + strip_elem->orig_height, + scene->r.xsch, + scene->r.ysch, + fit_method); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + } + } + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_strip_transform_fit(struct wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Strip Transform Set Fit"; + ot->idname = "SEQUENCER_OT_strip_transform_fit"; + + /* Api callbacks. */ + ot->exec = sequencer_strip_transform_fit_exec; + ot->poll = sequencer_edit_poll; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, + "fit_method", + scale_fit_methods, + SEQ_SCALE_TO_FIT, + "Fit Method", + "Scale fit fit_method"); +} + +/** \} */ diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 1ea4fb05d53..4c942a83f2b 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -71,7 +71,6 @@ struct ImBuf *sequencer_ibuf_get(struct Main *bmain, /* sequencer_edit.c */ struct View2D; void seq_rectf(struct Sequence *seq, struct rctf *rectf); -void boundbox_seq(struct Scene *scene, struct rctf *rect); struct Sequence *find_nearest_seq(struct Scene *scene, struct View2D *v2d, int *hand, @@ -145,6 +144,8 @@ void SEQUENCER_OT_enable_proxies(struct wmOperatorType *ot); void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot); void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot); +void SEQUENCER_OT_strip_transform_clear(struct wmOperatorType *ot); +void SEQUENCER_OT_strip_transform_fit(struct wmOperatorType *ot); /* sequencer_select.c */ void SEQUENCER_OT_select_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c index fb09afc6ca5..f11a879912c 100644 --- a/source/blender/editors/space_sequencer/sequencer_modifier.c +++ b/source/blender/editors/space_sequencer/sequencer_modifier.c @@ -34,6 +34,10 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "SEQ_iterator.h" +#include "SEQ_modifier.h" +#include "SEQ_relations.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" /* Own include. */ @@ -44,13 +48,13 @@ static bool strip_modifier_active_poll(bContext *C) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); if (seq) { - return BKE_sequence_supports_modifiers(seq); + return SEQ_sequence_supports_modifiers(seq); } } @@ -60,12 +64,12 @@ static bool strip_modifier_active_poll(bContext *C) static int strip_modifier_add_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); int type = RNA_enum_get(op->ptr, "type"); - BKE_sequence_modifier_new(seq, NULL, type); + SEQ_modifier_new(seq, NULL, type); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -102,21 +106,21 @@ void SEQUENCER_OT_strip_modifier_add(wmOperatorType *ot) static int strip_modifier_remove_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); char name[MAX_NAME]; SequenceModifierData *smd; RNA_string_get(op->ptr, "name", name); - smd = BKE_sequence_modifier_find_by_name(seq, name); + smd = SEQ_modifier_find_by_name(seq, name); if (!smd) { return OPERATOR_CANCELLED; } BLI_remlink(&seq->modifiers, smd); - BKE_sequence_modifier_free(smd); + SEQ_modifier_free(smd); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -153,7 +157,7 @@ enum { static int strip_modifier_move_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); char name[MAX_NAME]; int direction; SequenceModifierData *smd; @@ -161,7 +165,7 @@ static int strip_modifier_move_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "name", name); direction = RNA_enum_get(op->ptr, "direction"); - smd = BKE_sequence_modifier_find_by_name(seq, name); + smd = SEQ_modifier_find_by_name(seq, name); if (!smd) { return OPERATOR_CANCELLED; } @@ -179,7 +183,7 @@ static int strip_modifier_move_exec(bContext *C, wmOperator *op) } } - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -225,7 +229,7 @@ static int strip_modifier_copy_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Editing *ed = scene->ed; - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); Sequence *seq_iter; const int type = RNA_enum_get(op->ptr, "type"); @@ -245,19 +249,19 @@ static int strip_modifier_copy_exec(bContext *C, wmOperator *op) while (smd) { smd_tmp = smd->next; BLI_remlink(&seq_iter->modifiers, smd); - BKE_sequence_modifier_free(smd); + SEQ_modifier_free(smd); smd = smd_tmp; } BLI_listbase_clear(&seq_iter->modifiers); } } - BKE_sequence_modifier_list_copy(seq_iter, seq); + SEQ_modifier_list_copy(seq_iter, seq); } } SEQ_CURRENT_END; - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index bdf6e4ece7f..7bfc8600544 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -81,6 +81,8 @@ void sequencer_operatortypes(void) WM_operatortype_append(SEQUENCER_OT_change_path); WM_operatortype_append(SEQUENCER_OT_set_range_to_strips); + WM_operatortype_append(SEQUENCER_OT_strip_transform_clear); + WM_operatortype_append(SEQUENCER_OT_strip_transform_fit); /* sequencer_select.c */ WM_operatortype_append(SEQUENCER_OT_select_all); diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c index 2d23520814a..b04363a4f33 100644 --- a/source/blender/editors/space_sequencer/sequencer_proxy.c +++ b/source/blender/editors/space_sequencer/sequencer_proxy.c @@ -34,6 +34,9 @@ #include "BKE_main.h" #include "BKE_report.h" +#include "SEQ_iterator.h" +#include "SEQ_proxy.h" +#include "SEQ_relations.h" #include "SEQ_sequencer.h" #include "WM_api.h" @@ -90,14 +93,14 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog static void proxy_endjob(void *pjv) { ProxyJob *pj = pjv; - Editing *ed = BKE_sequencer_editing_get(pj->scene, false); + Editing *ed = SEQ_editing_get(pj->scene, false); LinkData *link; for (link = pj->queue.first; link; link = link->next) { SEQ_proxy_rebuild_finish(link->data, pj->stop); } - BKE_sequencer_free_imbuf(pj->scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(pj->scene, &ed->seqbase, false); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, pj->scene); } @@ -108,7 +111,7 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports) ProxyJob *pj; struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); ScrArea *area = CTX_wm_area(C); Sequence *seq; GSet *file_list; @@ -201,7 +204,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; GSet *file_list; @@ -225,7 +228,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) SEQ_proxy_rebuild(context, &stop, &do_update, &progress); SEQ_proxy_rebuild_finish(context, 0); } - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); } } SEQ_CURRENT_END; @@ -266,7 +269,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; bool proxy_25 = RNA_boolean_get(op->ptr, "proxy_25"); bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50"); diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index a6b2d7feae3..edbffa8f693 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -39,6 +39,8 @@ #include "RNA_define.h" +#include "SEQ_iterator.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" /* For menu, popup, icons, etc. */ @@ -198,13 +200,13 @@ void select_surround_from_last(Scene *scene) void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool deselect_all) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (deselect_all) { ED_sequencer_deselect_all(scene); } - BKE_sequencer_active_set(scene, seq); + SEQ_select_active_set(scene, seq); if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) { if (seq->strip) { @@ -223,7 +225,7 @@ void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool desel #if 0 static void select_neighbor_from_last(Scene *scene, int lr) { - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); Sequence *neighbor; bool changed = false; if (seq) { @@ -264,7 +266,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; if (action == SEL_TOGGLE) { @@ -331,7 +333,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; for (seq = ed->seqbasep->first; seq; seq = seq->next) { @@ -376,7 +378,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op) { View2D *v2d = UI_view2d_fromcontext(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + 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"); @@ -464,7 +466,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op) ret_value = OPERATOR_FINISHED; } - BKE_sequencer_active_set(scene, seq); + SEQ_select_active_set(scene, seq); if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) { if (seq->strip) { @@ -667,7 +669,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot) /* Run recursively to select linked. */ static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool linked) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq, *neighbor; bool changed = false; int isel; @@ -900,27 +902,84 @@ void SEQUENCER_OT_select_linked(wmOperatorType *ot) /** \name Select Handles Operator * \{ */ +enum { + SEQ_SELECT_HANDLES_SIDE_LEFT, + SEQ_SELECT_HANDLES_SIDE_RIGHT, + SEQ_SELECT_HANDLES_SIDE_BOTH, + SEQ_SELECT_HANDLES_SIDE_LEFT_NEIGHBOR, + SEQ_SELECT_HANDLES_SIDE_RIGHT_NEIGHBOR, + SEQ_SELECT_HANDLES_SIDE_BOTH_NEIGHBORS, +}; + +static const EnumPropertyItem prop_select_handles_side_types[] = { + {SEQ_SELECT_HANDLES_SIDE_LEFT, "LEFT", 0, "Left", ""}, + {SEQ_SELECT_HANDLES_SIDE_RIGHT, "RIGHT", 0, "Right", ""}, + {SEQ_SELECT_HANDLES_SIDE_BOTH, "BOTH", 0, "Both", ""}, + {SEQ_SELECT_HANDLES_SIDE_LEFT_NEIGHBOR, "LEFT_NEIGHBOR", 0, "Left Neighbor", ""}, + {SEQ_SELECT_HANDLES_SIDE_RIGHT_NEIGHBOR, "RIGHT_NEIGHBOR", 0, "Right Neighbor", ""}, + {SEQ_SELECT_HANDLES_SIDE_BOTH_NEIGHBORS, "BOTH_NEIGHBORS", 0, "Both Neighbors", ""}, + {0, NULL, 0, NULL, NULL}, +}; + static int sequencer_select_handles_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; int sel_side = RNA_enum_get(op->ptr, "side"); for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { + Sequence *l_neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, -1); + Sequence *r_neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, -1); + switch (sel_side) { - case SEQ_SIDE_LEFT: + case SEQ_SELECT_HANDLES_SIDE_LEFT: seq->flag &= ~SEQ_RIGHTSEL; seq->flag |= SEQ_LEFTSEL; break; - case SEQ_SIDE_RIGHT: + case SEQ_SELECT_HANDLES_SIDE_RIGHT: seq->flag &= ~SEQ_LEFTSEL; seq->flag |= SEQ_RIGHTSEL; break; - case SEQ_SIDE_BOTH: + case SEQ_SELECT_HANDLES_SIDE_BOTH: seq->flag |= SEQ_LEFTSEL | SEQ_RIGHTSEL; break; + case SEQ_SELECT_HANDLES_SIDE_LEFT_NEIGHBOR: + if (l_neighbor) { + if (!(l_neighbor->flag & SELECT)) { + l_neighbor->flag |= SEQ_RIGHTSEL; + } + } + break; + case SEQ_SELECT_HANDLES_SIDE_RIGHT_NEIGHBOR: + if (r_neighbor) { + if (!(r_neighbor->flag & SELECT)) { + r_neighbor->flag |= SEQ_LEFTSEL; + } + } + break; + case SEQ_SELECT_HANDLES_SIDE_BOTH_NEIGHBORS: + if (l_neighbor) { + if (!(l_neighbor->flag & SELECT)) { + l_neighbor->flag |= SEQ_RIGHTSEL; + } + } + if (r_neighbor) { + if (!(r_neighbor->flag & SELECT)) { + r_neighbor->flag |= SEQ_LEFTSEL; + } + break; + } + } + } + } + /* Select strips */ + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + if ((seq->flag & SEQ_LEFTSEL) || (seq->flag & SEQ_RIGHTSEL)) { + if (!(seq->flag & SELECT)) { + seq->flag |= SELECT; + recurs_sel_seq(seq); } } } @@ -949,8 +1008,8 @@ void SEQUENCER_OT_select_handles(wmOperatorType *ot) /* Properties. */ RNA_def_enum(ot->srna, "side", - prop_side_types, - SEQ_SIDE_BOTH, + prop_select_handles_side_types, + SEQ_SELECT_HANDLES_SIDE_BOTH, "Side", "The side of the handle that is selected"); } @@ -964,7 +1023,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); const bool extend = RNA_boolean_get(op->ptr, "extend"); const int side = RNA_enum_get(op->ptr, "side"); Sequence *seq; @@ -1038,7 +1097,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); const int sel_side = RNA_enum_get(op->ptr, "side"); const int frame_init = sel_side == SEQ_SIDE_LEFT ? INT_MIN : INT_MAX; @@ -1109,7 +1168,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 = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return OPERATOR_CANCELLED; @@ -1454,8 +1513,7 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int actseq->tmp = POINTER_FROM_INT(true); - for (BKE_sequence_iterator_begin(ed, &iter, true); iter.valid; - BKE_sequence_iterator_next(&iter)) { + for (SEQ_iterator_begin(ed, &iter, true); iter.valid; SEQ_iterator_next(&iter)) { seq = iter.seq; /* Ignore all seqs already selected. */ @@ -1486,8 +1544,8 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int changed = true; /* Unfortunately, we must restart checks from the beginning. */ - BKE_sequence_iterator_end(&iter); - BKE_sequence_iterator_begin(ed, &iter, true); + SEQ_iterator_end(&iter); + SEQ_iterator_begin(ed, &iter, true); } /* Video strips below active one, or any strip for audio (order doesn't matter here). */ @@ -1496,7 +1554,7 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int changed = true; } } - BKE_sequence_iterator_end(&iter); + SEQ_iterator_end(&iter); return changed; } @@ -1508,8 +1566,8 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int static int sequencer_select_grouped_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *seq, *actseq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *seq, *actseq = SEQ_select_active_get(scene); if (actseq == NULL) { BKE_report(op->reports, RPT_ERROR, "No active sequence!"); diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index 75d92d5f00d..8805d5af227 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -38,7 +38,9 @@ #include "RNA_define.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" /* For menu, popup, icons, etc. */ #include "ED_anim_api.h" @@ -87,8 +89,10 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op) rctf box; const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + Scene *scene = CTX_data_scene(C); + const Editing *ed = SEQ_editing_get(scene, false); - boundbox_seq(CTX_data_scene(C), &box); + SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &box); UI_view2d_smooth_view(C, region, &box, smooth_viewtx); return OPERATOR_FINISHED; } @@ -270,8 +274,8 @@ 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 = BKE_sequencer_editing_get(scene, false); - Sequence *last_seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *last_seq = SEQ_select_active_get(scene); Sequence *seq; rctf cur_new = v2d->cur; diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 45c7bac54f8..b11e2a32b87 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -52,6 +52,7 @@ #include "RNA_access.h" #include "SEQ_sequencer.h" +#include "SEQ_utils.h" #include "UI_interface.h" #include "UI_resources.h" @@ -99,7 +100,8 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce sseq->view = SEQ_VIEW_SEQUENCE; sseq->mainb = SEQ_DRAW_IMG_IMBUF; sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | - SEQ_ZOOM_TO_FIT; + SEQ_ZOOM_TO_FIT | SEQ_SHOW_STRIP_OVERLAY | SEQ_SHOW_STRIP_NAME | + SEQ_SHOW_STRIP_SOURCE | SEQ_SHOW_STRIP_DURATION; /* Tool header. */ region = MEM_callocN(sizeof(ARegion), "tool header for sequencer"); @@ -470,7 +472,7 @@ static int /*eContextResult*/ sequencer_context(const bContext *C, return CTX_RESULT_OK; } if (CTX_data_equals(member, "edit_mask")) { - Mask *mask = BKE_sequencer_mask_get(scene); + Mask *mask = SEQ_active_mask_get(scene); if (mask) { CTX_data_id_pointer_set(result, &mask->id); } @@ -706,7 +708,8 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *region) SpaceSeq *sseq = area->spacedata.first; Scene *scene = CTX_data_scene(C); wmWindowManager *wm = CTX_wm_manager(C); - const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW)); + const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) && + (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)); /* XXX temp fix for wrong setting in sseq->mainb */ if (sseq->mainb == SEQ_DRAW_SEQUENCE) { diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index bb71a9b11be..0f5ac5abe1d 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -357,7 +357,7 @@ static bool text_drop_paste_poll(bContext *UNUSED(C), static void text_drop_paste(wmDrag *drag, wmDropBox *drop) { char *text; - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID(drag, 0); /* copy drag path to properties */ text = RNA_path_full_ID_py(G_MAIN, id); diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c index c583634f440..84b7a6f6831 100644 --- a/source/blender/editors/space_text/text_header.c +++ b/source/blender/editors/space_text/text_header.c @@ -108,101 +108,3 @@ void TEXT_OT_start_find(wmOperatorType *ot) ot->exec = text_text_search_exec; ot->poll = text_properties_poll; } - -/******************** XXX popup menus *******************/ - -#if 0 -{ - /* RMB */ - - uiPopupMenu *pup; - - if (text) { - pup = UI_popup_menu_begin(C, IFACE_("Text"), ICON_NONE); - if (txt_has_sel(text)) { - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_cut"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_copy"); - } - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_paste"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save_as"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_run_script"); - UI_popup_menu_end(C, pup); - } - else { - pup = UI_popup_menu_begin(C, IFACE_("File"), ICON_NONE); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open"); - UI_popup_menu_end(C, pup); - } -} - -{ - /* Alt+Shift+E */ - - uiPopupMenu *pup; - - pup = UI_popup_menu_begin(C, IFACE_("Edit"), ICON_NONE); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_cut"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_copy"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_paste"); - UI_popup_menu_end(C, pup); -} - -{ - /* Alt+Shift+F */ - - uiPopupMenu *pup; - - if (text) { - pup = UI_popup_menu_begin(C, IFACE_("Text"), ICON_NONE); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save_as"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_run_script"); - UI_popup_menu_end(C, pup); - } - else { - pup = UI_popup_menu_begin(C, IFACE_("File"), ICON_NONE); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open"); - UI_popup_menu_end(C, pup); - } -} - -{ - /* Alt+Shift+V */ - - uiPopupMenu *pup; - - pup = UI_popup_menu_begin(C, IFACE_("Text"), ICON_NONE); - uiItemEnumO(layout, - "TEXT_OT_move", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Top of File"), - 0, - "type", - FILE_TOP); - uiItemEnumO(layout, - "TEXT_OT_move", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Bottom of File"), - 0, - "type", - FILE_BOTTOM); - uiItemEnumO(layout, - "TEXT_OT_move", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Page Up"), - 0, - "type", - PREV_PAGE); - uiItemEnumO(layout, - "TEXT_OT_move", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Page Down"), - 0, - "type", - NEXT_PAGE); - UI_popup_menu_end(C, pup); -} -#endif diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index f8b7c62686f..932bacfb8a0 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -2588,7 +2588,7 @@ static int text_scroll_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - txt_screen_skip(st, region, lines * U.wheellinescroll); + txt_screen_skip(st, region, lines * 3); ED_area_tag_redraw(CTX_wm_area(C)); diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c index d823530fd89..f05d6df9944 100644 --- a/source/blender/editors/space_userpref/userpref_ops.c +++ b/source/blender/editors/space_userpref/userpref_ops.c @@ -30,6 +30,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_preferences.h" #include "BKE_report.h" #include "RNA_access.h" @@ -92,7 +93,7 @@ static int preferences_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED static void PREFERENCES_OT_autoexec_path_add(wmOperatorType *ot) { - ot->name = "Add Autoexec Path"; + ot->name = "Add Auto-Execution Path"; ot->idname = "PREFERENCES_OT_autoexec_path_add"; ot->description = "Add path to exclude from auto-execution"; @@ -120,7 +121,7 @@ static int preferences_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op) static void PREFERENCES_OT_autoexec_path_remove(wmOperatorType *ot) { - ot->name = "Remove Autoexec Path"; + ot->name = "Remove Auto-Execution Path"; ot->idname = "PREFERENCES_OT_autoexec_path_remove"; ot->description = "Remove path to exclude from auto-execution"; @@ -133,9 +134,71 @@ static void PREFERENCES_OT_autoexec_path_remove(wmOperatorType *ot) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Add Asset Library Operator + * \{ */ + +static int preferences_asset_library_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) +{ + BKE_preferences_asset_library_add(&U, NULL, NULL); + U.runtime.is_dirty = true; + return OPERATOR_FINISHED; +} + +static void PREFERENCES_OT_asset_library_add(wmOperatorType *ot) +{ + ot->name = "Add Asset Library"; + ot->idname = "PREFERENCES_OT_asset_library_add"; + ot->description = + "Add a path to a .blend file to be used by the Asset Browser as source of assets"; + + ot->exec = preferences_asset_library_add_exec; + + ot->flag = OPTYPE_INTERNAL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Remove Asset Library Operator + * \{ */ + +static int preferences_asset_library_remove_exec(bContext *UNUSED(C), wmOperator *op) +{ + const int index = RNA_int_get(op->ptr, "index"); + bUserAssetLibrary *library = BLI_findlink(&U.asset_libraries, index); + if (library) { + BKE_preferences_asset_library_remove(&U, library); + U.runtime.is_dirty = true; + /* Trigger refresh for the Asset Browser. */ + WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, NULL); + } + return OPERATOR_FINISHED; +} + +static void PREFERENCES_OT_asset_library_remove(wmOperatorType *ot) +{ + ot->name = "Remove Asset Library"; + ot->idname = "PREFERENCES_OT_asset_library_remove"; + ot->description = + "Remove a path to a .blend file, so the Asset Browser will not attempt to show it anymore"; + + ot->exec = preferences_asset_library_remove_exec; + + ot->flag = OPTYPE_INTERNAL; + + RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000); +} + +/** \} */ + void ED_operatortypes_userpref(void) { WM_operatortype_append(PREFERENCES_OT_reset_default_theme); + WM_operatortype_append(PREFERENCES_OT_autoexec_path_add); WM_operatortype_append(PREFERENCES_OT_autoexec_path_remove); + + WM_operatortype_append(PREFERENCES_OT_asset_library_add); + WM_operatortype_append(PREFERENCES_OT_asset_library_remove); } diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 0371b4e271f..9242fc15021 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -22,13 +22,13 @@ set(INC ../../blenlib ../../blentranslation ../../bmesh + ../../depsgraph ../../draw ../../gpu ../../imbuf ../../makesdna ../../makesrna ../../render - ../../depsgraph ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 9f31e7a411d..3761f4ad7c6 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -461,6 +461,12 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *region) ED_view3d_stop_render_preview(wm, region); } +static bool view3d_drop_in_main_region_poll(bContext *C, const wmEvent *event) +{ + ScrArea *area = CTX_wm_area(C); + return ED_region_overlap_isect_any_xy(area, &event->x) == false; +} + static ID *view3d_drop_id_in_main_region_poll_id(bContext *C, wmDrag *drag, const wmEvent *event, @@ -470,7 +476,7 @@ static ID *view3d_drop_id_in_main_region_poll_id(bContext *C, if (ED_region_overlap_isect_any_xy(area, &event->x)) { return NULL; } - return WM_drag_ID(drag, id_type); + return view3d_drop_in_main_region_poll(C, event) ? WM_drag_get_local_ID(drag, id_type) : NULL; } static bool view3d_drop_id_in_main_region_poll(bContext *C, @@ -478,7 +484,11 @@ static bool view3d_drop_id_in_main_region_poll(bContext *C, const wmEvent *event, ID_Type id_type) { - return (view3d_drop_id_in_main_region_poll_id(C, drag, event, id_type) != NULL); + if (!view3d_drop_in_main_region_poll(C, event)) { + return false; + } + + return WM_drag_get_local_ID(drag, id_type) || WM_drag_get_asset_data(drag, id_type); } static bool view3d_ob_drop_poll(bContext *C, @@ -533,7 +543,7 @@ static bool view3d_ima_drop_poll(bContext *C, return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)); } - return WM_drag_ID(drag, ID_IM) != NULL; + return WM_drag_get_local_ID(drag, ID_IM) || WM_drag_get_asset_data(drag, ID_IM); } static bool view3d_ima_bg_is_camera_view(bContext *C) @@ -596,14 +606,14 @@ static bool view3d_volume_drop_poll(bContext *UNUSED(C), static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, ID_OB); + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_OB); RNA_string_set(drop->ptr, "name", id->name + 2); } static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, ID_GR); + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_GR); drop->opcontext = WM_OP_EXEC_DEFAULT; RNA_string_set(drop->ptr, "name", id->name + 2); @@ -611,14 +621,14 @@ static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop) static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); RNA_string_set(drop->ptr, "name", id->name + 2); } static void view3d_id_drop_copy_with_type(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID(drag, 0); RNA_string_set(drop->ptr, "name", id->name + 2); RNA_enum_set(drop->ptr, "type", GS(id->name)); @@ -626,7 +636,7 @@ static void view3d_id_drop_copy_with_type(wmDrag *drag, wmDropBox *drop) static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); if (id) { RNA_string_set(drop->ptr, "name", id->name + 2); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 9429da342a6..ebfa4f6d9af 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -4708,7 +4708,7 @@ static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op)) void VIEW3D_OT_view_persportho(wmOperatorType *ot) { /* identifiers */ - ot->name = "View Persp/Ortho"; + ot->name = "View Perspective/Orthographic"; ot->description = "Switch the current view from perspective/orthographic projection"; ot->idname = "VIEW3D_OT_view_persportho"; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index fdba74ed3a6..9b0ce27b1e3 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -315,8 +315,6 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, const float eps_bias = 0.0002f; float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */ - WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, true); - if (ruler_item) { RulerInteraction *inter = ruler_item->gz.interaction_data; float *co = ruler_item->co[inter->co_index]; @@ -388,12 +386,8 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); } - short snap_elem = ED_gizmotypes_snap_3d_update( + ED_gizmotypes_snap_3d_update( snap_gizmo, depsgraph, ruler_info->region, v3d, ruler_info->wm, mval_fl, co, NULL); - - if (snap_elem) { - WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, false); - } } return true; } @@ -1074,7 +1068,6 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel) if (!cancel) { if (ruler_info->state == RULER_STATE_DRAG) { - WM_gizmo_set_flag(ruler_info->snap_data.gizmo, WM_GIZMO_HIDDEN, false); RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint); ruler_state_set(ruler_info, RULER_STATE_NORMAL); } diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index 6d10aa5f957..bd71a768c0f 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -72,7 +72,7 @@ static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw * In this case we can't usefully project the mouse cursor onto the plane, * so use a fall-back plane instead. */ -const float eps_view_align = 1e-2f; +static const float eps_view_align = 1e-2f; /* -------------------------------------------------------------------- */ /** \name Local Types @@ -1357,7 +1357,6 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve const float mval_fl[2] = {UNPACK2(event->mval)}; /* Calculate the snap location on mouse-move or when toggling snap. */ - bool is_snap_found_prev = ipd->is_snap_found; ipd->is_snap_found = false; if (ipd->use_snap) { if (ipd->snap_gizmo != NULL) { @@ -1366,7 +1365,7 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve CTX_data_ensure_evaluated_depsgraph(C), ipd->region, ipd->v3d, - NULL, + G_MAIN->wm.first, mval_fl, ipd->snap_co, NULL)) { @@ -1376,12 +1375,6 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve } } - /* Workaround because test_select doesn't run at the same time as the modal operator. */ - if (is_snap_found_prev != ipd->is_snap_found) { - wmGizmoMap *gzmap = ipd->region->gizmo_map; - WM_gizmo_highlight_set(gzmap, ipd->is_snap_found ? ipd->snap_gizmo : NULL); - } - if (ipd->step_index == STEP_BASE) { if (ipd->is_snap_found) { closest_to_plane_normalized_v3( diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 5b400bbf60a..96bd25f85e7 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -2457,13 +2457,16 @@ static int view3d_select_exec(bContext *C, wmOperator *op) else if (obact && BKE_paint_select_face_test(obact)) { retval = paintface_mouse_select(C, obact, location, extend, deselect, toggle); if (!retval && deselect_all) { - retval = paintface_deselect_all_visible(C, CTX_data_active_object(C), SEL_DESELECT, false); + retval = paintface_deselect_all_visible(C, CTX_data_active_object(C), SEL_DESELECT, true); } } else if (BKE_paint_select_vert_test(obact)) { retval = ed_wpaint_vertex_select_pick(C, location, extend, deselect, toggle, obact); if (!retval && deselect_all) { retval = paintvert_deselect_all_visible(obact, SEL_DESELECT, false); + if (retval) { + paintvert_tag_select_update(C, obact); + } } } else { diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 1be9bd27c7a..2b7b8255068 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -1620,6 +1620,41 @@ void ED_view3d_to_object(const Depsgraph *depsgraph, BKE_object_apply_mat4_ex(ob, mat, ob_eval->parent, ob_eval->parentinv, true); } +bool ED_view3d_camera_to_view_selected(struct Main *bmain, + Depsgraph *depsgraph, + const Scene *scene, + Object *camera_ob) +{ + Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob); + float co[3]; /* the new location to apply */ + float scale; /* only for ortho cameras */ + + if (BKE_camera_view_frame_fit_to_scene(depsgraph, scene, camera_ob_eval, co, &scale)) { + ObjectTfmProtectedChannels obtfm; + float obmat_new[4][4]; + + if ((camera_ob_eval->type == OB_CAMERA) && + (((Camera *)camera_ob_eval->data)->type == CAM_ORTHO)) { + ((Camera *)camera_ob->data)->ortho_scale = scale; + } + + copy_m4_m4(obmat_new, camera_ob_eval->obmat); + copy_v3_v3(obmat_new[3], co); + + /* only touch location */ + BKE_object_tfm_protected_backup(camera_ob, &obtfm); + BKE_object_apply_mat4(camera_ob, obmat_new, true, true); + BKE_object_tfm_protected_restore(camera_ob, &obtfm, OB_LOCK_SCALE | OB_LOCK_ROT4D); + + /* notifiers */ + DEG_id_tag_update_ex(bmain, &camera_ob->id, ID_RECALC_TRANSFORM); + + return true; + } + + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index a24f59019f0..9d947384bf0 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -535,40 +535,18 @@ void VIEW3D_OT_camera_to_view(wmOperatorType *ot) * meant to take into account vertex/bone selection for eg. */ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); /* can be NULL */ Object *camera_ob = v3d ? v3d->camera : scene->camera; - Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob); - - float r_co[3]; /* the new location to apply */ - float r_scale; /* only for ortho cameras */ - if (camera_ob_eval == NULL) { + if (camera_ob == NULL) { BKE_report(op->reports, RPT_ERROR, "No active camera"); return OPERATOR_CANCELLED; } - /* this function does all the important stuff */ - if (BKE_camera_view_frame_fit_to_scene(depsgraph, scene, camera_ob_eval, r_co, &r_scale)) { - ObjectTfmProtectedChannels obtfm; - float obmat_new[4][4]; - - if ((camera_ob_eval->type == OB_CAMERA) && - (((Camera *)camera_ob_eval->data)->type == CAM_ORTHO)) { - ((Camera *)camera_ob->data)->ortho_scale = r_scale; - } - - copy_m4_m4(obmat_new, camera_ob_eval->obmat); - copy_v3_v3(obmat_new[3], r_co); - - /* only touch location */ - BKE_object_tfm_protected_backup(camera_ob, &obtfm); - BKE_object_apply_mat4(camera_ob, obmat_new, true, true); - BKE_object_tfm_protected_restore(camera_ob, &obtfm, OB_LOCK_SCALE | OB_LOCK_ROT4D); - - /* notifiers */ - DEG_id_tag_update(&camera_ob->id, ID_RECALC_TRANSFORM); + if (ED_view3d_camera_to_view_selected(bmain, depsgraph, scene, camera_ob)) { WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, camera_ob); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 73d6a376da6..a2eb68a1b71 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -22,12 +22,12 @@ set(INC ../../blenlib ../../blentranslation ../../bmesh + ../../depsgraph ../../gpu ../../ikplugin ../../makesdna ../../makesrna ../../render - ../../depsgraph ../../sequencer ../../windowmanager ../../../../intern/glew-mx diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 5969de5b5da..2b56b30be90 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -637,6 +637,14 @@ static bool transform_modal_item_poll(const wmOperator *op, int value) } break; } + case TFM_MODAL_TRANSLATE: + case TFM_MODAL_ROTATE: + case TFM_MODAL_RESIZE: { + if (!transform_mode_is_changeable(t->mode)) { + return false; + } + break; + } } return true; } @@ -876,11 +884,6 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } } - else if (t->mode == TFM_SEQ_SLIDE) { - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } else if (transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); @@ -922,11 +925,6 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } } - else if (t->mode == TFM_SHRINKFATTEN) { - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } else if (transform_mode_is_changeable(t->mode)) { /* Scale isn't normally very useful after extrude along normals, see T39756 */ if ((t->con.mode & CON_APPLY) && (t->orient[t->orient_curr].type == V3D_ORIENT_NORMAL)) { diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 227330e8524..91bf2bf8aac 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -52,12 +52,12 @@ struct SnapObjectContext; struct TransDataContainer; struct TransInfo; struct TransSnap; -struct TransformOrientation; struct ViewLayer; struct bContext; struct wmEvent; struct wmKeyConfig; struct wmKeyMap; +struct wmOperator; struct wmTimer; /** #TransInfo.redraw */ diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index c23ee5b771c..c81c954bd0a 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -1438,7 +1438,7 @@ void animrecord_check_state(TransInfo *t, struct Object *ob) /* only push down if action is more than 1-2 frames long */ calc_action_range(adt->action, &astart, &aend, 1); if (aend > astart + 2.0f) { - NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action); + NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action, ID_IS_OVERRIDE_LIBRARY(id)); /* clear reference to action now that we've pushed it onto the stack */ id_us_min(&adt->action->id); diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index b753572ea7b..59fcd016020 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -29,12 +29,9 @@ struct FCurve; struct ListBase; struct Object; struct TransData; -struct TransDataContainer; struct TransDataCurveHandleFlags; struct TransInfo; struct bContext; -struct bKinematicConstraint; -struct bPoseChannel; /* transform_convert.c */ void transform_autoik_update(TransInfo *t, short mode); diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index a7301161570..e9b2273b343 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -164,21 +164,21 @@ static void autokeyframe_pose( /* only if bone name matches too... * NOTE: this will do constraints too, but those are ok to do here too? */ - if (pchanName && 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); - } - 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); } } diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c index 8f18f6a8c96..fa60a88a45b 100644 --- a/source/blender/editors/transform/transform_convert_nla.c +++ b/source/blender/editors/transform/transform_convert_nla.c @@ -462,6 +462,12 @@ void recalcData_nla(TransInfo *t) * - we need to calculate both, * as only one may have been altered by transform if only 1 handle moved. */ + /* In LibOverride case, we cannot move strips across tracks that come from the linked data. */ + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(tdn->id); + if (BKE_nlatrack_is_nonlocal_in_liboverride(tdn->id, tdn->nlt)) { + continue; + } + delta_y1 = ((int)tdn->h1[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex); delta_y2 = ((int)tdn->h2[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex); @@ -477,10 +483,11 @@ void recalcData_nla(TransInfo *t) if (delta > 0) { for (track = tdn->nlt->next, n = 0; (track) && (n < delta); track = track->next, n++) { /* check if space in this track for the strip */ - if (BKE_nlatrack_has_space(track, strip->start, strip->end)) { + if (BKE_nlatrack_has_space(track, strip->start, strip->end) && + !BKE_nlatrack_is_nonlocal_in_liboverride(tdn->id, tdn->nlt)) { /* move strip to this track */ BLI_remlink(&tdn->nlt->strips, strip); - BKE_nlatrack_add_strip(track, strip); + BKE_nlatrack_add_strip(track, strip, is_liboverride); tdn->nlt = track; tdn->trackIndex++; @@ -496,10 +503,11 @@ void recalcData_nla(TransInfo *t) for (track = tdn->nlt->prev, n = 0; (track) && (n < delta); track = track->prev, n++) { /* check if space in this track for the strip */ - if (BKE_nlatrack_has_space(track, strip->start, strip->end)) { + if (BKE_nlatrack_has_space(track, strip->start, strip->end) && + !BKE_nlatrack_is_nonlocal_in_liboverride(tdn->id, tdn->nlt)) { /* move strip to this track */ BLI_remlink(&tdn->nlt->strips, strip); - BKE_nlatrack_add_strip(track, strip); + BKE_nlatrack_add_strip(track, strip, is_liboverride); tdn->nlt = track; tdn->trackIndex--; diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 3f86ef3e81b..ebb0b6823a3 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -32,7 +32,11 @@ #include "ED_markers.h" +#include "SEQ_relations.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" +#include "SEQ_utils.h" #include "UI_view2d.h" @@ -84,8 +88,8 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c Scene *scene = t->scene; int cfra = CFRA; - int left = BKE_sequence_tx_get_final_left(seq, true); - int right = BKE_sequence_tx_get_final_right(seq, true); + int left = SEQ_transform_get_left_handle_frame(seq, true); + int right = SEQ_transform_get_right_handle_frame(seq, true); if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) { *r_recursive = false; @@ -186,7 +190,7 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c /* Meta's can only directly be moved between channels since they * don't have their start and length set directly (children affect that) * since this Meta is nested we don't need any of its data in fact. - * BKE_sequence_calc() will update its settings when run on the top-level meta. */ + * SEQ_time_update_sequence() will update its settings when run on the top-level meta. */ *r_flag = 0; *r_count = 0; *r_recursive = true; @@ -235,16 +239,16 @@ static TransData *SeqToTransData( /* Use seq_tx_get_final_left() and an offset here * so transform has the left hand location of the strip. * tdsq->start_offset is used when flushing the tx data back */ - start_left = BKE_sequence_tx_get_final_left(seq, false); + start_left = SEQ_transform_get_left_handle_frame(seq, false); td2d->loc[0] = start_left; tdsq->start_offset = start_left - seq->start; /* use to apply the original location */ break; case SEQ_LEFTSEL: - start_left = BKE_sequence_tx_get_final_left(seq, false); + start_left = SEQ_transform_get_left_handle_frame(seq, false); td2d->loc[0] = start_left; break; case SEQ_RIGHTSEL: - td2d->loc[0] = BKE_sequence_tx_get_final_right(seq, false); + td2d->loc[0] = SEQ_transform_get_right_handle_frame(seq, false); break; } @@ -366,7 +370,7 @@ static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts) static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data) { - Editing *ed = BKE_sequencer_editing_get(t->scene, false); + Editing *ed = SEQ_editing_get(t->scene, false); if (ed != NULL) { @@ -388,7 +392,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c for (a = 0; a < t->total; a++, td++) { if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) { seq = ((TransDataSeq *)td->extra)->seq; - BKE_sequence_base_shuffle(seqbasep, seq, t->scene); + SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene); } seq_prev = seq; @@ -429,7 +433,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c } else { /* Tag seq with a non zero value, used by - * BKE_sequence_base_shuffle_time to identify the ones to shuffle */ + * SEQ_transform_seqbase_shuffle_time to identify the ones to shuffle */ if (seq->depth == 0) { seq->tmp = (void *)1; } @@ -455,7 +459,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c } } - BKE_sequence_base_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); + SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); for (seq = seqbasep->first; seq; seq = seq->next) { if (seq->machine >= MAXSEQ * 2) { @@ -467,10 +471,10 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c } } - BKE_sequence_base_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); + SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); } else { - BKE_sequence_base_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); + SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); } if (has_effect_any) { @@ -480,7 +484,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c seq = ((TransDataSeq *)td->extra)->seq; if ((seq != seq_prev)) { if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } } } @@ -493,8 +497,8 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c seq = ((TransDataSeq *)td->extra)->seq; if ((seq != seq_prev) && (seq->depth == 0)) { if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) { - if (BKE_sequence_test_overlap(seqbasep, seq)) { - BKE_sequence_base_shuffle(seqbasep, seq, t->scene); + if (SEQ_transform_test_overlap(seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene); } } } @@ -509,18 +513,18 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c /* We might want to build a list of effects that need to be updated during transform */ if (seq->type & SEQ_TYPE_EFFECT) { if (seq->seq1 && seq->seq1->flag & SELECT) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } else if (seq->seq2 && seq->seq2->flag & SELECT) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } else if (seq->seq3 && seq->seq3->flag & SELECT) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } } } - BKE_sequencer_sort(t->scene); + SEQ_sort(t->scene); } else { /* Canceled, need to update the strips display */ @@ -528,10 +532,10 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c seq = ((TransDataSeq *)td->extra)->seq; if ((seq != seq_prev) && (seq->depth == 0)) { if (seq->flag & SEQ_OVERLAP) { - BKE_sequence_base_shuffle(seqbasep, seq, t->scene); + SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene); } - BKE_sequence_calc_disp(t->scene, seq); + SEQ_time_update_sequence_bounds(t->scene, seq); } seq_prev = seq; } @@ -553,7 +557,7 @@ void createTransSeqData(TransInfo *t) #define XXX_DURIAN_ANIM_TX_HACK Scene *scene = t->scene; - Editing *ed = BKE_sequencer_editing_get(t->scene, false); + Editing *ed = SEQ_editing_get(t->scene, false); TransData *td = NULL; TransData2D *td2d = NULL; TransDataSeq *tdsq = NULL; @@ -640,21 +644,21 @@ BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int s /* Calculate this strip and all nested strips. * Children are ALWAYS transformed first so we don't need to do this in another loop. */ - BKE_sequence_calc(sce, seq); + SEQ_time_update_sequence(sce, seq); } else { - BKE_sequence_calc_disp(sce, seq); + SEQ_time_update_sequence_bounds(sce, seq); } if (sel_flag == SELECT) { - BKE_sequencer_offset_animdata(sce, seq, seq->start - old_start); + SEQ_offset_animdata(sce, seq, seq->start - old_start); } } static void flushTransSeq(TransInfo *t) { /* Editing null check already done */ - ListBase *seqbasep = BKE_sequencer_editing_get(t->scene, false)->seqbasep; + ListBase *seqbasep = SEQ_editing_get(t->scene, false)->seqbasep; int a, new_frame; TransData *td = NULL; @@ -681,7 +685,7 @@ static void flushTransSeq(TransInfo *t) switch (tdsq->sel_flag) { case SELECT: #ifdef SEQ_TX_NESTED_METAS - if ((seq->depth != 0 || BKE_sequence_tx_test(seq))) { + if ((seq->depth != 0 || SEQ_transform_sequence_can_be_translated(seq))) { /* for meta's, their children move */ seq->start = new_frame - tdsq->start_offset; } @@ -697,18 +701,18 @@ static void flushTransSeq(TransInfo *t) } break; case SEQ_LEFTSEL: /* no vertical transform */ - BKE_sequence_tx_set_final_left(seq, new_frame); - BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); + SEQ_transform_set_left_handle_frame(seq, new_frame); + SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); /* todo - move this into aftertrans update? - old seq tx needed it anyway */ - BKE_sequence_single_fix(seq); + SEQ_transform_fix_single_image_seq_offsets(seq); break; case SEQ_RIGHTSEL: /* no vertical transform */ - BKE_sequence_tx_set_final_right(seq, new_frame); - BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); + SEQ_transform_set_right_handle_frame(seq, new_frame); + SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); /* todo - move this into aftertrans update? - old seq tx needed it anyway */ - BKE_sequence_single_fix(seq); + SEQ_transform_fix_single_image_seq_offsets(seq); break; } @@ -743,12 +747,12 @@ static void flushTransSeq(TransInfo *t) /* calc all meta's then effects T27953. */ for (seq = seqbasep->first; seq; seq = seq->next) { if (seq->type == SEQ_TYPE_META && seq->flag & SELECT) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } } for (seq = seqbasep->first; seq; seq = seq->next) { if (seq->seq1 || seq->seq2 || seq->seq3) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } } @@ -759,7 +763,7 @@ static void flushTransSeq(TransInfo *t) seq = tdsq->seq; if ((seq != seq_prev) && (seq->depth != 0)) { if (seq->seq1 || seq->seq2 || seq->seq3) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } } } @@ -777,7 +781,7 @@ static void flushTransSeq(TransInfo *t) if (seq->depth == 0) { /* test overlap, displays red outline */ seq->flag &= ~SEQ_OVERLAP; - if (BKE_sequence_test_overlap(seqbasep, seq)) { + if (SEQ_transform_test_overlap(seqbasep, seq)) { seq->flag |= SEQ_OVERLAP; } } @@ -800,7 +804,7 @@ void recalcData_sequencer(TransInfo *t) Sequence *seq = tdsq->seq; if (seq != seq_prev) { - BKE_sequence_invalidate_cache_composite(t->scene, seq); + SEQ_relations_invalidate_cache_composite(t->scene, seq); } seq_prev = seq; diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c index dfa5c164acf..7ccfd0149bd 100644 --- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c @@ -32,6 +32,7 @@ #include "ED_screen.h" #include "WM_api.h" +#include "WM_types.h" #include "UI_interface.h" @@ -45,6 +46,18 @@ /** \name Transform (Sequencer Slide) * \{ */ +static eRedrawFlag seq_slide_handleEvent(struct TransInfo *t, const wmEvent *event) +{ + BLI_assert(t->mode == TFM_SEQ_SLIDE); + wmKeyMapItem *kmi = t->custom.mode.data; + if (kmi && event->type == kmi->type && event->val == kmi->val) { + /* Allows the 'Expand to fit' effect to be enabled as a toogle. */ + t->flag ^= T_ALT_TRANSFORM; + return TREDRAW_HARD; + } + return TREDRAW_NOTHING; +} + static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRAW_STR]) { char tvec[NUM_STR_REP_LEN * 3]; @@ -60,12 +73,11 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRA ofs += BLI_snprintf( str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text); - if (t->keymap) { - wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE); - if (kmi) { - ofs += WM_keymap_item_to_string(kmi, false, str + ofs, UI_MAX_DRAW_STR - ofs); - } + wmKeyMapItem *kmi = t->custom.mode.data; + if (kmi) { + ofs += WM_keymap_item_to_string(kmi, false, str + ofs, UI_MAX_DRAW_STR - ofs); } + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" or Alt) Expand to fit %s"), @@ -91,7 +103,7 @@ static void applySeqSlideValue(TransInfo *t, const float val[2]) static void applySeqSlide(TransInfo *t, const int mval[2]) { char str[UI_MAX_DRAW_STR]; - float values_final[2] = {0.0f}; + float values_final[3] = {0.0f}; snapSequenceBounds(t, mval); if (applyNumInput(&t->num, values_final)) { @@ -126,6 +138,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2]) void initSeqSlide(TransInfo *t) { t->transform = applySeqSlide; + t->handleEvent = seq_slide_handleEvent; initMouseInputMode(t, &t->mouse, INPUT_VECTOR); @@ -142,5 +155,10 @@ void initSeqSlide(TransInfo *t) * (supporting frames in addition to "natural" time...). */ t->num.unit_type[0] = B_UNIT_NONE; t->num.unit_type[1] = B_UNIT_NONE; + + if (t->keymap) { + /* Workaround to use the same key as the modal keymap. */ + t->custom.mode.data = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE); + } } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c index cdea388529f..2a5c631df41 100644 --- a/source/blender/editors/transform/transform_mode_shrink_fatten.c +++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c @@ -32,6 +32,7 @@ #include "ED_screen.h" #include "WM_api.h" +#include "WM_types.h" #include "UI_interface.h" @@ -45,6 +46,18 @@ /** \name Transform (Shrink-Fatten) * \{ */ +static eRedrawFlag shrinkfatten_handleEvent(struct TransInfo *t, const wmEvent *event) +{ + BLI_assert(t->mode == TFM_SHRINKFATTEN); + wmKeyMapItem *kmi = t->custom.mode.data; + if (kmi && event->type == kmi->type && event->val == kmi->val) { + /* Allows the 'Even Thickness' effect to be enabled as a toogle. */ + t->flag ^= T_ALT_TRANSFORM; + return TREDRAW_HARD; + } + return TREDRAW_NOTHING; +} + static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) { float distance; @@ -77,12 +90,11 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) } ofs += BLI_strncpy_rlen(str + ofs, ", (", sizeof(str) - ofs); - if (t->keymap) { - wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE); - if (kmi) { - ofs += WM_keymap_item_to_string(kmi, false, str + ofs, sizeof(str) - ofs); - } + wmKeyMapItem *kmi = t->custom.mode.data; + if (kmi) { + ofs += WM_keymap_item_to_string(kmi, false, str + ofs, sizeof(str) - ofs); } + BLI_snprintf(str + ofs, sizeof(str) - ofs, TIP_(" or Alt) Even Thickness %s"), @@ -121,6 +133,7 @@ void initShrinkFatten(TransInfo *t) else { t->mode = TFM_SHRINKFATTEN; t->transform = applyShrinkFatten; + t->handleEvent = shrinkfatten_handleEvent; initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); @@ -134,6 +147,11 @@ void initShrinkFatten(TransInfo *t) t->num.unit_type[0] = B_UNIT_LENGTH; t->flag |= T_NO_CONSTRAINT; + + if (t->keymap) { + /* Workaround to use the same key as the modal keymap. */ + t->custom.mode.data = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE); + } } } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 90c1f241338..8597c372537 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -377,6 +377,9 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) else { mul_v3_m3v3(global_dir, t->spacemtx, global_dir); } + if (t->flag & T_2D_EDIT) { + removeAspectRatio(t, global_dir); + } } else { copy_v3_v3(global_dir, t->values); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 5153fdedcae..5d758a6c6c6 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -717,7 +717,7 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) "use_automerge_and_split", 0, "Auto Merge & Split", - "Forces the use of Auto Merge & Split"); + "Forces the use of Auto Merge and Split"); RNA_def_property_flag(prop, PROP_HIDDEN); } } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index f1c4c243780..d407cea0033 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -42,6 +42,7 @@ #include "RNA_access.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "WM_types.h" @@ -1409,7 +1410,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2]) const int frame_curr = round_fl_to_int(xmouse); /* Now find the closest sequence. */ - const int frame_near = BKE_sequencer_find_next_prev_edit( + const int frame_near = SEQ_time_find_next_prev_edit( t->scene, frame_curr, SEQ_SIDE_BOTH, true, false, true); const int frame_snap = transform_convert_sequencer_get_snap_bound(t); diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index 5bee572c603..db8ec943bfd 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -25,8 +25,6 @@ /* For enum. */ #include "DNA_space_types.h" -struct SnapObjectParams; - bool peelObjectsTransform(struct TransInfo *t, const float mval[2], const bool use_peel_object, diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index 49417a54472..4fded419b5b 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -27,6 +27,7 @@ #include "BLI_listbase.h" #include "DNA_ID.h" +#include "DNA_collection_types.h" #include "DNA_node_types.h" #include "DNA_object_enums.h" #include "DNA_object_types.h" diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index c88169778f7..0aab3810254 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -39,6 +39,7 @@ set(SRC ed_transverts.c ed_util.c ed_util_imbuf.c + ed_util_ops.c gizmo_utils.c numinput.c select_utils.c @@ -47,6 +48,7 @@ set(SRC ../include/BIF_glutil.h ../include/ED_anim_api.h ../include/ED_armature.h + ../include/ED_asset.h ../include/ED_buttons.h ../include/ED_clip.h ../include/ED_curve.h diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 76c261c9cba..5d2584c566d 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -35,6 +35,7 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "BLI_fileops.h" #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" @@ -44,6 +45,7 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_icons.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" @@ -51,6 +53,7 @@ #include "BKE_object.h" #include "BKE_packedFile.h" #include "BKE_paint.h" +#include "BKE_report.h" #include "BKE_screen.h" #include "BKE_undo_system.h" #include "BKE_workspace.h" @@ -64,6 +67,7 @@ #include "ED_object.h" #include "ED_outliner.h" #include "ED_paint.h" +#include "ED_render.h" #include "ED_space_api.h" #include "ED_util.h" @@ -481,22 +485,102 @@ void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_i } } -static int ed_flush_edits_exec(bContext *C, wmOperator *UNUSED(op)) +static bool lib_id_preview_editing_poll(bContext *C) { - Main *bmain = CTX_data_main(C); - ED_editors_flush_edits(bmain); + const PointerRNA idptr = CTX_data_pointer_get(C, "id"); + BLI_assert(!idptr.data || RNA_struct_is_ID(idptr.type)); + + const ID *id = idptr.data; + if (!id) { + return false; + } + if (ID_IS_LINKED(id)) { + CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit external library data")); + return false; + } + if (ID_IS_OVERRIDE_LIBRARY(id)) { + CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit previews of overridden library data")); + return false; + } + if (!BKE_previewimg_id_get_p(id)) { + CTX_wm_operator_poll_msg_set(C, TIP_("Data-block does not support previews")); + return false; + } + + return true; +} + +static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op) +{ + char path[FILE_MAX]; + + RNA_string_get(op->ptr, "filepath", path); + + if (!BLI_is_file(path)) { + BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path); + return OPERATOR_CANCELLED; + } + + PointerRNA idptr = CTX_data_pointer_get(C, "id"); + ID *id = idptr.data; + + BKE_previewimg_id_custom_set(id, path); + + WM_event_add_notifier(C, NC_ASSET, NULL); + + return OPERATOR_FINISHED; +} + +void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot) +{ + ot->name = "Load Custom Preview"; + ot->description = "Choose an image to help identify the data-block visually"; + ot->idname = "ED_OT_lib_id_load_custom_preview"; + + /* api callbacks */ + ot->poll = lib_id_preview_editing_poll; + ot->exec = lib_id_load_custom_preview_exec; + ot->invoke = WM_operator_filesel; + + /* flags */ + ot->flag = OPTYPE_INTERNAL; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, + FILE_SPECIAL, + FILE_OPENFILE, + WM_FILESEL_FILEPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_DEFAULT); +} + +static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PointerRNA idptr = CTX_data_pointer_get(C, "id"); + ID *id = idptr.data; + + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + + PreviewImage *preview = BKE_previewimg_id_get(id); + if (preview) { + BKE_previewimg_clear(preview); + } + UI_icon_render_id(C, NULL, id, true, true); + + WM_event_add_notifier(C, NC_ASSET, NULL); + return OPERATOR_FINISHED; } -void ED_OT_flush_edits(wmOperatorType *ot) +void ED_OT_lib_id_generate_preview(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Flush Edits"; - ot->description = "Flush edit data from active editing modes"; - ot->idname = "ED_OT_flush_edits"; + ot->name = "Generate Preview"; + ot->description = "Create an automatic preview for the selected data-block"; + ot->idname = "ED_OT_lib_id_generate_preview"; /* api callbacks */ - ot->exec = ed_flush_edits_exec; + ot->poll = lib_id_preview_editing_poll; + ot->exec = lib_id_generate_preview_exec; /* flags */ ot->flag = OPTYPE_INTERNAL; diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c index b832d9a1d86..0f2e280251f 100644 --- a/source/blender/editors/util/ed_util_imbuf.c +++ b/source/blender/editors/util/ed_util_imbuf.c @@ -42,6 +42,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "SEQ_render.h" #include "SEQ_sequencer.h" #include "UI_view2d.h" @@ -564,7 +565,7 @@ bool ED_imbuf_sample_poll(bContext *C) return false; } - return sseq && BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL; + return sseq && SEQ_editing_get(CTX_data_scene(C), false) != NULL; } return false; diff --git a/source/blender/editors/util/ed_util_ops.c b/source/blender/editors/util/ed_util_ops.c new file mode 100644 index 00000000000..d8d1a64c1ee --- /dev/null +++ b/source/blender/editors/util/ed_util_ops.c @@ -0,0 +1,155 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edutil + * + * Utility operators for UI data or for the UI to use. + */ + +#include <string.h> + +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_lib_id.h" +#include "BKE_main.h" +#include "BKE_report.h" + +#include "DNA_windowmanager_types.h" + +#include "ED_util.h" + +#include "RNA_access.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +static int lib_fake_user_toggle_exec(bContext *C, wmOperator *op) +{ + PropertyPointerRNA pprop; + PointerRNA idptr = PointerRNA_NULL; + + UI_context_active_but_prop_get_templateID(C, &pprop.ptr, &pprop.prop); + + if (pprop.prop) { + idptr = RNA_property_pointer_get(&pprop.ptr, pprop.prop); + } + + if ((pprop.prop == NULL) || RNA_pointer_is_null(&idptr) || !RNA_struct_is_ID(idptr.type)) { + BKE_report( + op->reports, RPT_ERROR, "Incorrect context for running data-block fake user toggling"); + return OPERATOR_CANCELLED; + } + + ID *id = idptr.data; + + if ((id->lib != NULL) || (ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) { + BKE_report(op->reports, RPT_ERROR, "Data-block type does not support fake user"); + return OPERATOR_CANCELLED; + } + + if (ID_FAKE_USERS(id)) { + id_fake_user_clear(id); + } + else { + id_fake_user_set(id); + } + + return OPERATOR_FINISHED; +} + +static void ED_OT_lib_fake_user_toggle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Toggle Fake User"; + ot->description = "Save this data-block even if it has no users"; + ot->idname = "ED_OT_lib_fake_user_toggle"; + + /* api callbacks */ + ot->exec = lib_fake_user_toggle_exec; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +static int lib_unlink_exec(bContext *C, wmOperator *op) +{ + PropertyPointerRNA pprop; + PointerRNA idptr; + + UI_context_active_but_prop_get_templateID(C, &pprop.ptr, &pprop.prop); + + if (pprop.prop) { + idptr = RNA_property_pointer_get(&pprop.ptr, pprop.prop); + } + + if ((pprop.prop == NULL) || RNA_pointer_is_null(&idptr) || !RNA_struct_is_ID(idptr.type)) { + BKE_report( + op->reports, RPT_ERROR, "Incorrect context for running data-block fake user toggling"); + return OPERATOR_CANCELLED; + } + + memset(&idptr, 0, sizeof(idptr)); + RNA_property_pointer_set(&pprop.ptr, pprop.prop, idptr, NULL); + RNA_property_update(C, &pprop.ptr, pprop.prop); + + return OPERATOR_FINISHED; +} + +static void ED_OT_lib_unlink(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Unlink Data-Block"; + ot->description = "Remove a usage of a data-block, clearing the assignment"; + ot->idname = "ED_OT_lib_unlink"; + + /* api callbacks */ + ot->exec = lib_unlink_exec; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +static int ed_flush_edits_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + ED_editors_flush_edits(bmain); + return OPERATOR_FINISHED; +} + +static void ED_OT_flush_edits(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Flush Edits"; + ot->description = "Flush edit data from active editing modes"; + ot->idname = "ED_OT_flush_edits"; + + /* api callbacks */ + ot->exec = ed_flush_edits_exec; + + /* flags */ + ot->flag = OPTYPE_INTERNAL; +} + +void ED_operatortypes_edutils(void) +{ + WM_operatortype_append(ED_OT_lib_fake_user_toggle); + WM_operatortype_append(ED_OT_lib_unlink); + WM_operatortype_append(ED_OT_flush_edits); +} diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index 8e4a3df920e..1c8a56e0608 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -35,11 +35,11 @@ set(INC set(SRC uvedit_buttons.c uvedit_draw.c + uvedit_islands.c uvedit_ops.c uvedit_parametrizer.c uvedit_path.c uvedit_rip.c - uvedit_islands.c uvedit_select.c uvedit_smart_stitch.c uvedit_unwrap_ops.c diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 306f8a2c561..28567234fab 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -25,7 +25,6 @@ struct BMFace; struct BMLoop; -struct Image; struct Object; struct Scene; struct SpaceImage; diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 5b3d858329a..aac5b96f737 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -1812,7 +1812,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot) -FLT_MAX, FLT_MAX, "Location", - "Cursor location in normalized (0.0-1.0) coordinates", + "Cursor location in normalized (0.0 to 1.0) coordinates", -10.0f, 10.0f); } diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 6dac31794b4..c1d222c9368 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -2808,7 +2808,7 @@ void UV_OT_stitch(wmOperatorType *ot) RNA_def_boolean(ot->srna, "midpoint_snap", 0, - "Snap At Midpoint", + "Snap at Midpoint", "UVs are stitched at midpoint instead of at static island"); RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams", "Clear seams of stitched edges"); RNA_def_enum(ot->srna, |