diff options
Diffstat (limited to 'source/blender/editors')
179 files changed, 7055 insertions, 4575 deletions
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt index 978bd772b6f..ce6778a1ff9 100644 --- a/source/blender/editors/animation/CMakeLists.txt +++ b/source/blender/editors/animation/CMakeLists.txt @@ -51,6 +51,7 @@ set(SRC keyframes_general.c keyframing.c keyingsets.c + time_scrub_ui.c anim_intern.h ) diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 6d1ee08d5e9..00025112835 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -485,16 +485,10 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi static void acf_summary_name(bAnimListElem *UNUSED(ale), char *name) { if (name) { - BLI_strncpy(name, IFACE_("Dope Sheet Summary"), ANIM_CHAN_NAME_SIZE); + BLI_strncpy(name, IFACE_("Summary"), ANIM_CHAN_NAME_SIZE); } } -// FIXME: this is really a temp icon I think -static int acf_summary_icon(bAnimListElem *UNUSED(ale)) -{ - return ICON_BORDERMOVE; -} - /* check if some setting exists for this channel */ static bool acf_summary_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), @@ -557,7 +551,7 @@ static bAnimChannelType ACF_SUMMARY = { acf_summary_name, /* name */ NULL, /* name prop */ - acf_summary_icon, /* icon */ + NULL, /* icon */ acf_summary_setting_valid, /* has setting */ acf_summary_setting_flag, /* flag for setting */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 6e0277d5fff..9e09fc485a6 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -55,6 +55,7 @@ #include "DEG_depsgraph_build.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "ED_anim_api.h" #include "ED_armature.h" @@ -2531,17 +2532,6 @@ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectm SpaceNla *snla = (SpaceNla *)ac->sl; View2D *v2d = &ac->ar->v2d; rctf rectf; - float ymin, ymax; - - /* set initial y extents */ - if (ac->datatype == ANIMCONT_NLA) { - ymin = (float)(-NLACHANNEL_HEIGHT(snla)); - ymax = 0.0f; - } - else { - ymin = 0.0f; - ymax = (float)(-ACHANNEL_HEIGHT(ac)); - } /* convert border-region to view coordinates */ UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin + 2, &rectf.xmin, &rectf.ymin); @@ -2551,8 +2541,17 @@ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectm filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + float ymax; + if (ac->datatype == ANIMCONT_NLA) { + ymax = NLACHANNEL_FIRST_TOP(ac); + } + else { + ymax = ACHANNEL_FIRST_TOP(ac); + } + /* loop over data, doing box select */ for (ale = anim_data.first; ale; ale = ale->next) { + float ymin; if (ac->datatype == ANIMCONT_NLA) { ymin = ymax - NLACHANNEL_STEP(snla); } @@ -2729,32 +2728,25 @@ static int animchannels_channel_get(bAnimContext *ac, const int mval[2]) ar = ac->ar; v2d = &ar->v2d; - /* Figure out which channel user clicked in. - * - * Note: although channels technically start at (y = ACHANNEL_FIRST), - * we need to adjust by half a channel's height so that the tops of channels get caught ok. - * Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use ACHANNEL_HEIGHT_HALF. - */ + /* Figure out which channel user clicked in. */ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); if (ac->datatype == ANIMCONT_NLA) { SpaceNla *snla = (SpaceNla *)ac->sl; - UI_view2d_listview_view_to_cell(v2d, - NLACHANNEL_NAMEWIDTH, + UI_view2d_listview_view_to_cell(NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, - (float)NLACHANNEL_HEIGHT_HALF(snla), + NLACHANNEL_FIRST_TOP(ac), x, y, NULL, &channel_index); } else { - UI_view2d_listview_view_to_cell(v2d, - ACHANNEL_NAMEWIDTH, + UI_view2d_listview_view_to_cell(ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(ac), 0, - (float)ACHANNEL_HEIGHT_HALF(ac), + ACHANNEL_FIRST_TOP(ac), x, y, NULL, @@ -3206,19 +3198,12 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmE selectmode = SELECT_REPLACE; } - /* figure out which channel user clicked in - * - * Note: - * although channels technically start at (y = ACHANNEL_FIRST), - * we need to adjust by half a channel's height so that the tops of channels get caught ok. - * Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use ACHANNEL_HEIGHT_HALF. - */ + /* figure out which channel user clicked in */ UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y); - UI_view2d_listview_view_to_cell(v2d, - ACHANNEL_NAMEWIDTH, + UI_view2d_listview_view_to_cell(ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(&ac), 0, - (float)ACHANNEL_HEIGHT_HALF(&ac), + ACHANNEL_FIRST_TOP(&ac), x, y, NULL, diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index b94d0e3ada7..a228d819286 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1823,7 +1823,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, } /* outliner restrict-flag */ - if (ob->restrictflag & OB_RESTRICT_VIEW) { + if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { continue; } } @@ -3022,7 +3022,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_m } /* outliner restrict-flag */ - if (ob->restrictflag & OB_RESTRICT_VIEW) { + if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { return false; } } diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 66cdae07a36..876bc9ae3e4 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -481,7 +481,9 @@ static void draw_markers_background(rctf *rect) uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - const unsigned char shade[4] = {0, 0, 0, 16}; + unsigned char shade[4]; + UI_GetThemeColor4ubv(TH_SCRUBBING_BACKGROUND, shade); + immUniformColor4ubv(shade); GPU_blend(true); diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 2a8702802aa..fe079eb59a0 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -1249,7 +1249,8 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op) UI_context_update_anim_flag(C); DEG_relations_tag_update(CTX_data_main(C)); - DEG_id_tag_update(ptr.id.data, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + DEG_id_tag_update(ptr.id.data, ID_RECALC_ANIMATION); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); // XXX diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 5214c5f78fa..be8de66a262 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -315,8 +315,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo clear_fcurve_keys(fcu); /* check if curve is really unused and if it is, return signal for deletion */ - if ((list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) && - (fcu->driver == NULL)) { + if (BKE_fcurve_is_empty(fcu)) { AnimData *adt = ale->adt; ANIM_fcurve_delete_from_animdata(ac, adt, fcu); ale->key_data = NULL; diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index a0433b49b16..2dc17c5c397 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1307,8 +1307,8 @@ static bool insert_keyframe_fcurve_value(Main *bmain, * - if we're replacing keyframes only, DO NOT create new F-Curves if they do not exist yet * but still try to get the F-Curve if it exists... */ - FCurve *fcu = verify_fcurve( - bmain, act, group, ptr, rna_path, array_index, (flag & INSERTKEY_REPLACE) == 0); + bool can_create_curve = (flag & (INSERTKEY_REPLACE | INSERTKEY_AVAILABLE)) == 0; + FCurve *fcu = verify_fcurve(bmain, act, group, ptr, rna_path, array_index, can_create_curve); /* we may not have a F-Curve when we're replacing only... */ if (fcu) { @@ -1432,7 +1432,7 @@ short insert_keyframe(Main *bmain, /* Key the entire array. */ if (array_index == -1 || force_all) { /* In force mode, if any of the curves succeeds, drop the replace mode and restart. */ - if (force_all && (flag & INSERTKEY_REPLACE) != 0) { + if (force_all && (flag & (INSERTKEY_REPLACE | INSERTKEY_AVAILABLE)) != 0) { int exclude = -1; for (array_index = 0; array_index < value_count; array_index++) { @@ -1455,7 +1455,7 @@ short insert_keyframe(Main *bmain, } if (exclude != -1) { - flag &= ~INSERTKEY_REPLACE; + flag &= ~(INSERTKEY_REPLACE | INSERTKEY_AVAILABLE); for (array_index = 0; array_index < value_count; array_index++) { if (array_index != exclude) { @@ -1557,8 +1557,7 @@ static bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra) delete_fcurve_key(fcu, i, 1); /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && - (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) { + if (BKE_fcurve_is_empty(fcu)) { ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); } diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c new file mode 100644 index 00000000000..37e7eab74d4 --- /dev/null +++ b/source/blender/editors/animation/time_scrub_ui.c @@ -0,0 +1,214 @@ +/* + * 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) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edanimation + */ + +#include "BKE_context.h" + +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "GPU_state.h" + +#include "ED_time_scrub_ui.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_interface_icons.h" +#include "UI_view2d.h" +#include "UI_resources.h" + +#include "DNA_scene_types.h" + +#include "BLI_rect.h" +#include "BLI_math.h" +#include "BLI_string.h" +#include "BLI_timecode.h" + +#include "RNA_access.h" + +static void get_scrubbing_region_rect(const ARegion *ar, rcti *rect) +{ + rect->xmin = 0; + rect->xmax = ar->winx; + rect->ymax = ar->winy; + rect->ymin = rect->ymax - UI_SCRUBBING_MARGIN_Y; +} + +static int get_centered_text_y(const rcti *rect) +{ + return BLI_rcti_cent_y(rect) - UI_DPI_FAC * 4; +} + +static void draw_background(const rcti *rect) +{ + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformThemeColor(TH_SCRUBBING_BACKGROUND); + + GPU_blend(true); + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + + GPU_blend(false); + + immUnbindProgram(); +} + +static void get_current_time_str( + const Scene *scene, bool display_seconds, int frame, uint max_len, char *r_str) +{ + if (display_seconds) { + BLI_timecode_string_from_time(r_str, max_len, 0, FRA2TIME(frame), FPS, U.timecode_style); + } + else { + BLI_snprintf(r_str, max_len, "%d", frame); + } +} + +static void draw_current_frame(const Scene *scene, + bool display_seconds, + const View2D *v2d, + const rcti *scrubbing_region_rect, + int current_frame) +{ + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + const unsigned char color[] = {255, 255, 255, 255}; + int frame_x = UI_view2d_view_to_region_x(v2d, current_frame); + + char frame_str[64]; + get_current_time_str(scene, display_seconds, current_frame, sizeof(frame_str), frame_str); + float text_width = UI_fontstyle_string_width(fstyle, frame_str); + float box_width = MAX2(text_width + 8 * UI_DPI_FAC, 24 * UI_DPI_FAC); + float box_padding = 3 * UI_DPI_FAC; + + float bg_color[4]; + UI_GetThemeColorShade4fv(TH_CFRAME, -5, bg_color); + + UI_draw_roundbox_corner_set(UI_CNR_ALL); + + UI_draw_roundbox_3fvAlpha(true, + frame_x - box_width / 2 + U.pixelsize / 2, + scrubbing_region_rect->ymin + box_padding, + frame_x + box_width / 2 + U.pixelsize / 2, + scrubbing_region_rect->ymax - box_padding, + 4 * UI_DPI_FAC, + bg_color, + 1.0f); + + UI_GetThemeColorShade4fv(TH_CFRAME, 5, bg_color); + UI_draw_roundbox_aa(false, + frame_x - box_width / 2 + U.pixelsize / 2, + scrubbing_region_rect->ymin + box_padding, + frame_x + box_width / 2 + U.pixelsize / 2, + scrubbing_region_rect->ymax - box_padding, + 4 * UI_DPI_FAC, + bg_color); + + UI_fontstyle_draw_simple(fstyle, + frame_x - text_width / 2 + U.pixelsize / 2, + get_centered_text_y(scrubbing_region_rect), + frame_str, + color); +} + +void ED_scrubbing_draw(const ARegion *ar, + const Scene *scene, + bool display_seconds, + bool discrete_frames) +{ + const View2D *v2d = &ar->v2d; + + GPU_matrix_push_projection(); + wmOrtho2_region_pixelspace(ar); + + rcti scrubbing_region_rect; + get_scrubbing_region_rect(ar, &scrubbing_region_rect); + + draw_background(&scrubbing_region_rect); + + rcti numbers_rect = scrubbing_region_rect; + numbers_rect.ymin = get_centered_text_y(&scrubbing_region_rect) - 4 * UI_DPI_FAC; + if (discrete_frames) { + UI_view2d_draw_scale_x__discrete_frames_or_seconds( + ar, v2d, &numbers_rect, scene, display_seconds, TH_TEXT); + } + else { + UI_view2d_draw_scale_x__frames_or_seconds( + ar, v2d, &numbers_rect, scene, display_seconds, TH_TEXT); + } + + draw_current_frame(scene, display_seconds, v2d, &scrubbing_region_rect, scene->r.cfra); + + GPU_matrix_pop_projection(); +} + +bool ED_event_in_scrubbing_region(const ARegion *ar, const wmEvent *event) +{ + rcti rect = ar->winrct; + rect.ymin = rect.ymax - UI_SCRUBBING_MARGIN_Y; + return BLI_rcti_isect_pt(&rect, event->x, event->y); +} + +void ED_channel_search_draw(const bContext *C, ARegion *ar, bDopeSheet *dopesheet) +{ + GPU_matrix_push_projection(); + wmOrtho2_region_pixelspace(ar); + + rcti rect; + rect.xmin = 0; + rect.xmax = ceilf(ar->sizex * UI_DPI_FAC); + rect.ymin = ar->sizey * UI_DPI_FAC - UI_SCRUBBING_MARGIN_Y; + rect.ymax = ceilf(ar->sizey * UI_DPI_FAC); + + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_BACK); + immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + immUnbindProgram(); + + uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); + + PointerRNA ptr; + RNA_pointer_create(&CTX_wm_screen(C)->id, &RNA_DopeSheet, dopesheet, &ptr); + PropertyRNA *prop = RNA_struct_find_property(&ptr, "filter_text"); + + int padding = 2 * UI_DPI_FAC; + uiDefAutoButR(block, + &ptr, + prop, + -1, + "", + ICON_NONE, + rect.xmin + padding, + rect.ymin + padding, + BLI_rcti_size_x(&rect) - 2 * padding, + BLI_rcti_size_y(&rect) - 2 * padding); + + UI_block_end(C, block); + UI_block_draw(C, block); + + GPU_matrix_pop_projection(); +} diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 6c2d9fe8f42..569eb7e2e04 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -210,6 +210,8 @@ void POSELIB_OT_apply_pose(struct wmOperatorType *ot); void POSE_OT_push(struct wmOperatorType *ot); void POSE_OT_relax(struct wmOperatorType *ot); +void POSE_OT_push_rest(struct wmOperatorType *ot); +void POSE_OT_relax_rest(struct wmOperatorType *ot); void POSE_OT_breakdown(struct wmOperatorType *ot); void POSE_OT_propagate(struct wmOperatorType *ot); diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 083967d5d41..9a1582679a4 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -180,7 +180,17 @@ void ED_armature_bone_rename(Main *bmain, if (bone) { unique_bone_name(arm, newname); + + if (arm->bonehash) { + BLI_assert(BLI_ghash_haskey(arm->bonehash, bone->name)); + BLI_ghash_remove(arm->bonehash, bone->name, NULL, NULL); + } + BLI_strncpy(bone->name, newname, MAXBONENAME); + + if (arm->bonehash) { + BLI_ghash_insert(arm->bonehash, bone->name, bone); + } } else { return; diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index b53ae813f10..a29d0f5f158 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -146,6 +146,8 @@ void ED_operatortypes_armature(void) /* POSE SLIDING */ WM_operatortype_append(POSE_OT_push); WM_operatortype_append(POSE_OT_relax); + WM_operatortype_append(POSE_OT_push_rest); + WM_operatortype_append(POSE_OT_relax_rest); WM_operatortype_append(POSE_OT_breakdown); } diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index b2ca1d84520..2c61818d902 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -66,10 +66,16 @@ /* *************************************** Join *************************************** */ /* NOTE: no operator define here as this is exported to the Object-level operator */ -static void joined_armature_fix_links_constraints( - Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone, ListBase *lb) +static void joined_armature_fix_links_constraints(Main *bmain, + Object *ob, + Object *tarArm, + Object *srcArm, + bPoseChannel *pchan, + EditBone *curbone, + ListBase *lb) { bConstraint *con; + bool changed = false; for (con = lb->first; con; con = con->next) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); @@ -84,10 +90,12 @@ static void joined_armature_fix_links_constraints( if (ct->tar == srcArm) { if (ct->subtarget[0] == '\0') { ct->tar = tarArm; + changed = true; } else if (STREQ(ct->subtarget, pchan->name)) { ct->tar = tarArm; BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget)); + changed = true; } } } @@ -104,13 +112,21 @@ static void joined_armature_fix_links_constraints( if (data->act) { BKE_action_fix_paths_rename( &tarArm->id, data->act, "pose.bones[", pchan->name, curbone->name, 0, 0, false); + + DEG_id_tag_update_ex(bmain, &data->act->id, ID_RECALC_COPY_ON_WRITE); } } } + + if (changed) { + DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_COPY_ON_WRITE); + } } /* userdata for joined_armature_fix_animdata_cb() */ typedef struct tJoinArmature_AdtFixData { + Main *bmain; + Object *srcArm; Object *tarArm; @@ -129,6 +145,7 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data ID *dst_id = &afd->tarArm->id; GHashIterator gh_iter; + bool changed = false; /* Fix paths - If this is the target object, it will have some "dirty" paths */ if ((id == src_id) && strstr(fcu->rna_path, "pose.bones[")) { @@ -142,6 +159,8 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data fcu->rna_path = BKE_animsys_fix_rna_path_rename( id, fcu->rna_path, "pose.bones", old_name, new_name, 0, 0, false); + changed = true; + /* we don't want to apply a second remapping on this driver now, * so stop trying names, but keep fixing drivers */ @@ -163,6 +182,8 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data if (dtar->id == src_id) { dtar->id = dst_id; + changed = true; + /* also check on the subtarget... * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own * little twists so that we know that it isn't going to clobber the wrong data @@ -193,6 +214,10 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data DRIVER_TARGETS_LOOPER_END; } } + + if (changed) { + DEG_id_tag_update_ex(afd->bmain, id, ID_RECALC_COPY_ON_WRITE); + } } /* Helper function for armature joining - link fixing */ @@ -210,13 +235,14 @@ static void joined_armature_fix_links( pose = ob->pose; for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) { joined_armature_fix_links_constraints( - tarArm, srcArm, pchan, curbone, &pchant->constraints); + bmain, ob, tarArm, srcArm, pchan, curbone, &pchant->constraints); } } /* fix object-level constraints */ if (ob != srcArm) { - joined_armature_fix_links_constraints(tarArm, srcArm, pchan, curbone, &ob->constraints); + joined_armature_fix_links_constraints( + bmain, ob, tarArm, srcArm, pchan, curbone, &ob->constraints); } /* See if an object is parented to this armature */ @@ -231,6 +257,8 @@ static void joined_armature_fix_links( /* make tar armature be new parent */ ob->parent = tarArm; + + DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_COPY_ON_WRITE); } } } @@ -286,6 +314,7 @@ int join_armature_exec(bContext *C, wmOperator *op) BLI_assert(ob_active->data != ob_iter->data); /* init callback data for fixing up AnimData links later */ + afd.bmain = bmain; afd.srcArm = ob_iter; afd.tarArm = ob_active; afd.names_map = BLI_ghash_str_new("join_armature_adt_fix"); diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index fbbb68d2003..23ddf77e63d 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -70,7 +70,7 @@ Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases, EditBone *ebone = NULL; /* TODO(campbell): optimize, eg: sort & binary search. */ for (uint base_index = 0; base_index < bases_len; base_index++) { - if (bases[base_index]->object->select_id == hit_object) { + if (bases[base_index]->object->runtime.select_id == hit_object) { base = bases[base_index]; break; } @@ -94,7 +94,7 @@ Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects, EditBone *ebone = NULL; /* TODO(campbell): optimize, eg: sort & binary search. */ for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - if (objects[ob_index]->select_id == hit_object) { + if (objects[ob_index]->runtime.select_id == hit_object) { ob = objects[ob_index]; break; } @@ -118,7 +118,7 @@ Base *ED_armature_base_and_bone_from_select_buffer(Base **bases, Bone *bone = NULL; /* TODO(campbell): optimize, eg: sort & binary search. */ for (uint base_index = 0; base_index < bases_len; base_index++) { - if (bases[base_index]->object->select_id == hit_object) { + if (bases[base_index]->object->runtime.select_id == hit_object) { base = bases[base_index]; break; } @@ -300,6 +300,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv const bool sel = !RNA_boolean_get(op->ptr, "deselect"); view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); Base *base = NULL; bone = get_nearest_bone(C, event->mval, true, &base); @@ -1817,6 +1818,7 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const Base *base_dst = NULL; view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); ebone_src = arm->act_edbone; ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst); diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index b23081cd6fa..27076f84c7f 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -127,7 +127,6 @@ void bone_free(bArmature *arm, EditBone *bone) if (bone->prop) { IDP_FreeProperty(bone->prop); - MEM_freeN(bone->prop); } /* Clear references from other edit bones. */ @@ -650,6 +649,7 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm) Object *obt; /* armature bones */ + BKE_armature_bone_hash_free(arm); BKE_armature_bonelist_free(&arm->bonebase); arm->act_bone = NULL; @@ -754,6 +754,8 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm) /* Finalize definition of restpose data (roll, bone_mat, arm_mat, head/tail...). */ armature_finalize_restpose(&arm->bonebase, arm->edbo); + BKE_armature_bone_hash_make(arm); + /* so all users of this armature should get rebuilt */ for (obt = bmain->objects.first; obt; obt = obt->id.next) { if (obt->data == arm) { @@ -774,7 +776,6 @@ void ED_armature_edit_free(struct bArmature *arm) for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { if (eBone->prop) { IDP_FreeProperty(eBone->prop); - MEM_freeN(eBone->prop); } } @@ -808,7 +809,6 @@ void ED_armature_ebone_listbase_free(ListBase *lb) if (ebone->prop) { IDP_FreeProperty(ebone->prop); - MEM_freeN(ebone->prop); } MEM_freeN(ebone); diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index cf64210ebdb..954beda7777 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -65,7 +65,7 @@ #include "armature_intern.h" -#define DEBUG_TIME +#undef DEBUG_TIME #include "PIL_time.h" #ifdef DEBUG_TIME @@ -197,38 +197,6 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre ListBase targets = {NULL, NULL}; bool free_depsgraph = false; - /* Override depsgraph with a filtered, simpler copy */ - if (!current_frame_only && G.debug_value != -1) { - DEG_FilterQuery query = {{0}}; - - DEG_FilterTarget *dft_ob = MEM_callocN(sizeof(DEG_FilterTarget), "DEG_FilterTarget"); - dft_ob->id = &ob->id; - BLI_addtail(&query.targets, dft_ob); - -#ifdef DEBUG_TIME - TIMEIT_START(filter_pose_depsgraph); -#endif - - depsgraph = DEG_graph_filter(depsgraph, bmain, &query); - -#ifdef DEBUG_TIME - TIMEIT_END(filter_pose_depsgraph); -#endif - - free_depsgraph = true; - MEM_freeN(dft_ob); - -#ifdef DEBUG_TIME - TIMEIT_START(filter_pose_update); -#endif - - BKE_scene_graph_update_tagged(depsgraph, bmain); - -#ifdef DEBUG_TIME - TIMEIT_END(filter_pose_update); -#endif - } - /* set flag to force recalc, then grab the relevant bones to target */ ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS; animviz_get_object_motionpaths(ob, &targets); diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 7b31897766d..4bcfdc700b3 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -1018,7 +1018,6 @@ static void poselib_backup_free_data(tPoseLib_PreviewData *pld) /* free custom data */ if (plb->oldprops) { IDP_FreeProperty(plb->oldprops); - MEM_freeN(plb->oldprops); } /* free backup element now */ diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index d683c599f7b..9bc204c9e3b 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -134,6 +134,8 @@ typedef enum ePoseSlide_Modes { POSESLIDE_PUSH = 0, /* exaggerate the pose... */ POSESLIDE_RELAX, /* soften the pose... */ POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */ + POSESLIDE_PUSH_REST, + POSESLIDE_RELAX_REST, } ePoseSlide_Modes; /* Transforms/Channels to Affect */ @@ -627,6 +629,103 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) MEM_freeN(path); } +static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], float default_value) +{ + /* We only slide to the rest pose. So only use the default rest pose value */ + const int lock = pso->axislock; + for (int idx = 0; idx < 3; idx++) { + if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) || + ((lock & PS_LOCK_Z) && (idx == 2))) { + float diff_val = default_value - vec[idx]; + if (pso->mode == POSESLIDE_RELAX_REST) { + vec[idx] += pso->percentage * diff_val; + } + else { + /* Push */ + vec[idx] -= pso->percentage * diff_val; + } + } + } +} + +static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4], bool quat) +{ + /* We only slide to the rest pose. So only use the default rest pose value */ + float default_values[] = {1.0f, 0.0f, 0.0f, 0.0f}; + if (!quat) { + /* Axis Angle */ + default_values[0] = 0.0f; + default_values[2] = 1.0f; + } + for (int idx = 0; idx < 4; idx++) { + float diff_val = default_values[idx] - vec[idx]; + if (pso->mode == POSESLIDE_RELAX_REST) { + vec[idx] += pso->percentage * diff_val; + } + else { + /* Push */ + vec[idx] -= pso->percentage * diff_val; + } + } +} + +/* apply() - perform the pose sliding between the current pose and the rest pose */ +static void pose_slide_rest_pose_apply(bContext *C, tPoseSlideOp *pso) +{ + tPChanFCurveLink *pfl; + + /* for each link, handle each set of transforms */ + for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) { + /* valid transforms for each PoseChannel should have been noted already + * - sliding the pose should be a straightforward exercise for location+rotation, + * but rotations get more complicated since we may want to use quaternion blending + * for quaternions instead... + */ + bPoseChannel *pchan = pfl->pchan; + + if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) { + /* calculate these for the 'location' vector, and use location curves */ + pose_slide_rest_pose_apply_vec3(pso, pchan->loc, 0.0f); + } + + if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) { + /* calculate these for the 'scale' vector, and use scale curves */ + pose_slide_rest_pose_apply_vec3(pso, pchan->size, 1.0f); + } + + if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) { + /* everything depends on the rotation mode */ + if (pchan->rotmode > 0) { + /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */ + pose_slide_rest_pose_apply_vec3(pso, pchan->eul, 0.0f); + } + else if (pchan->rotmode == ROT_MODE_AXISANGLE) { + pose_slide_rest_pose_apply_other_rot(pso, pchan->quat, false); + } + else { + /* quaternions - use quaternion blending */ + pose_slide_rest_pose_apply_other_rot(pso, pchan->quat, true); + } + } + + if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) { + /* bbone properties - they all start a "bbone_" prefix */ + // TODO Not implemented + // pose_slide_apply_props(pso, pfl, "bbone_"); + } + + if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) { + /* Not strictly a transform, but custom properties contribute + * to the pose produced in many rigs (e.g. the facial rigs used in Sintel). */ + // TODO Not implemented + // pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */ + } + } + + /* depsgraph updates + redraws */ + pose_slide_refresh(C, pso); +} + /* apply() - perform the pose sliding based on weighting various poses */ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso) { @@ -888,7 +987,12 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p /* initial apply for operator... */ /* TODO: need to calculate percentage for initial round too... */ - pose_slide_apply(C, pso); + if (pso->mode != POSESLIDE_PUSH_REST && pso->mode != POSESLIDE_RELAX_REST) { + pose_slide_apply(C, pso); + } + else { + pose_slide_rest_pose_apply(C, pso); + } /* depsgraph updates + redraws */ pose_slide_refresh(C, pso); @@ -1122,7 +1226,12 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) pose_slide_reset(pso); /* apply... */ - pose_slide_apply(C, pso); + if (pso->mode != POSESLIDE_PUSH_REST && pso->mode != POSESLIDE_RELAX_REST) { + pose_slide_apply(C, pso); + } + else { + pose_slide_rest_pose_apply(C, pso); + } } /* still running... */ @@ -1140,7 +1249,12 @@ static void pose_slide_cancel(bContext *UNUSED(C), wmOperator *op) static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso) { /* settings should have been set up ok for applying, so just apply! */ - pose_slide_apply(C, pso); + if (pso->mode != POSESLIDE_PUSH_REST && pso->mode != POSESLIDE_RELAX_REST) { + pose_slide_apply(C, pso); + } + else { + pose_slide_rest_pose_apply(C, pso); + } /* insert keyframes if needed */ pose_slide_autoKeyframe(C, pso); @@ -1200,7 +1314,7 @@ static void pose_slide_opdef_properties(wmOperatorType *ot) /* ------------------------------------ */ -/* invoke() - for 'push' mode */ +/* invoke() - for 'push from breakdown' mode */ static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *event) { tPoseSlideOp *pso; @@ -1242,9 +1356,9 @@ static int pose_slide_push_exec(bContext *C, wmOperator *op) void POSE_OT_push(wmOperatorType *ot) { /* identifiers */ - ot->name = "Push Pose"; + ot->name = "Push Pose from Breakdown"; ot->idname = "POSE_OT_push"; - ot->description = "Exaggerate the current pose"; + ot->description = "Exaggerate the current pose in regards to the breakdown pose"; /* callbacks */ ot->exec = pose_slide_push_exec; @@ -1262,7 +1376,7 @@ void POSE_OT_push(wmOperatorType *ot) /* ........................ */ -/* invoke() - for 'relax' mode */ +/* invoke() - for 'relax to breakdown' mode */ static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *event) { tPoseSlideOp *pso; @@ -1304,9 +1418,9 @@ static int pose_slide_relax_exec(bContext *C, wmOperator *op) void POSE_OT_relax(wmOperatorType *ot) { /* identifiers */ - ot->name = "Relax Pose"; + ot->name = "Relax Pose to Breakdown"; ot->idname = "POSE_OT_relax"; - ot->description = "Make the current pose more similar to its surrounding ones"; + ot->description = "Make the current pose more similar to its breakdown pose"; /* callbacks */ ot->exec = pose_slide_relax_exec; @@ -1323,6 +1437,129 @@ void POSE_OT_relax(wmOperatorType *ot) } /* ........................ */ +/* invoke() - for 'push from rest pose' mode */ +static int pose_slide_push_rest_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + tPoseSlideOp *pso; + + /* initialize data */ + if (pose_slide_init(C, op, POSESLIDE_PUSH_REST) == 0) { + pose_slide_exit(op); + return OPERATOR_CANCELLED; + } + else { + pso = op->customdata; + } + + /* initialise percentage so that it won't pop on first mouse move */ + pose_slide_mouse_update_percentage(pso, op, event); + + /* do common setup work */ + return pose_slide_invoke_common(C, op, pso); +} + +/* exec() - for push */ +static int pose_slide_push_rest_exec(bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso; + + /* initialize data (from RNA-props) */ + if (pose_slide_init(C, op, POSESLIDE_PUSH_REST) == 0) { + pose_slide_exit(op); + return OPERATOR_CANCELLED; + } + else { + pso = op->customdata; + } + + /* do common exec work */ + return pose_slide_exec_common(C, op, pso); +} + +void POSE_OT_push_rest(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Push Pose from Rest Pose"; + ot->idname = "POSE_OT_push_rest"; + ot->description = "Push the current pose further away from the rest pose"; + + /* callbacks */ + ot->exec = pose_slide_push_rest_exec; + ot->invoke = pose_slide_push_rest_invoke; + ot->modal = pose_slide_modal; + ot->cancel = pose_slide_cancel; + ot->poll = ED_operator_posemode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_USE_EVAL_DATA; + + /* Properties */ + pose_slide_opdef_properties(ot); +} + +/* ........................ */ + +/* invoke() - for 'relax' mode */ +static int pose_slide_relax_rest_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + tPoseSlideOp *pso; + + /* initialize data */ + if (pose_slide_init(C, op, POSESLIDE_RELAX_REST) == 0) { + pose_slide_exit(op); + return OPERATOR_CANCELLED; + } + else { + pso = op->customdata; + } + + /* initialise percentage so that it won't pop on first mouse move */ + pose_slide_mouse_update_percentage(pso, op, event); + + /* do common setup work */ + return pose_slide_invoke_common(C, op, pso); +} + +/* exec() - for relax */ +static int pose_slide_relax_rest_exec(bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso; + + /* initialize data (from RNA-props) */ + if (pose_slide_init(C, op, POSESLIDE_RELAX_REST) == 0) { + pose_slide_exit(op); + return OPERATOR_CANCELLED; + } + else { + pso = op->customdata; + } + + /* do common exec work */ + return pose_slide_exec_common(C, op, pso); +} + +void POSE_OT_relax_rest(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Relax Pose to Rest Pose"; + ot->idname = "POSE_OT_relax_rest"; + ot->description = "Make the current pose more similar to the rest pose"; + + /* callbacks */ + ot->exec = pose_slide_relax_rest_exec; + ot->invoke = pose_slide_relax_rest_invoke; + ot->modal = pose_slide_modal; + ot->cancel = pose_slide_cancel; + ot->poll = ED_operator_posemode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_USE_EVAL_DATA; + + /* Properties */ + pose_slide_opdef_properties(ot); +} + +/* ........................ */ /* invoke() - for 'breakdown' mode */ static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event) diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 6207d5412cf..ed728714c5b 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -59,6 +59,9 @@ #include "ED_screen.h" #include "ED_util.h" +#include "UI_interface.h" +#include "UI_resources.h" + #include "armature_intern.h" /* ********************************************** */ @@ -87,6 +90,229 @@ static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Objec } } +/* Sets the bone head, tail and roll to match the supplied parameters. */ +static void applyarmature_set_edit_position(EditBone *curbone, + const float pose_mat[4][4], + const float new_tail[3], + float r_new_arm_mat[4][4]) +{ + /* Simply copy the head/tail values from pchan over to curbone. */ + copy_v3_v3(curbone->head, pose_mat[3]); + copy_v3_v3(curbone->tail, new_tail); + + /* Fix roll: + * 1. find auto-calculated roll value for this bone now + * 2. remove this from the 'visual' y-rotation + */ + { + float premat[3][3], pmat[3][3]; + float delta[3]; + + /* Obtain new auto y-rotation. */ + sub_v3_v3v3(delta, curbone->tail, curbone->head); + + copy_m3_m4(pmat, pose_mat); + mat3_vec_to_roll(pmat, delta, &curbone->roll); + + /* Compute new rest pose matrix if requested. */ + if (r_new_arm_mat) { + vec_roll_to_mat3(delta, curbone->roll, premat); + copy_m4_m3(r_new_arm_mat, premat); + copy_v3_v3(r_new_arm_mat[3], pose_mat[3]); + } + } +} + +/* Copy properties over from pchan to curbone and reset channels. */ +static void applyarmature_transfer_properties(EditBone *curbone, + bPoseChannel *pchan, + const bPoseChannel *pchan_eval) +{ + /* Combine pose and rest values for bendy bone settings, + * then clear the pchan values (so we don't get a double-up). + */ + if (pchan->bone->segments > 1) { + /* Combine rest/pose values. */ + curbone->curve_in_x += pchan_eval->curve_in_x; + curbone->curve_in_y += pchan_eval->curve_in_y; + curbone->curve_out_x += pchan_eval->curve_out_x; + curbone->curve_out_y += pchan_eval->curve_out_y; + curbone->roll1 += pchan_eval->roll1; + curbone->roll2 += pchan_eval->roll2; + curbone->ease1 += pchan_eval->ease1; + curbone->ease2 += pchan_eval->ease2; + + curbone->scale_in_x *= pchan_eval->scale_in_x; + curbone->scale_in_y *= pchan_eval->scale_in_y; + curbone->scale_out_x *= pchan_eval->scale_out_x; + curbone->scale_out_y *= pchan_eval->scale_out_y; + + /* Reset pose values. */ + pchan->curve_in_x = pchan->curve_out_x = 0.0f; + pchan->curve_in_y = pchan->curve_out_y = 0.0f; + pchan->roll1 = pchan->roll2 = 0.0f; + pchan->ease1 = pchan->ease2 = 0.0f; + pchan->scale_in_x = pchan->scale_in_y = 1.0f; + pchan->scale_out_x = pchan->scale_out_y = 1.0f; + } + + /* Clear transform values for pchan. */ + zero_v3(pchan->loc); + zero_v3(pchan->eul); + unit_qt(pchan->quat); + unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); + pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f; + + /* Set anim lock. */ + curbone->flag |= BONE_UNKEYED; +} + +/* Adjust the current edit position of the bone using the pose space matrix. */ +static void applyarmature_adjust_edit_position(bArmature *arm, + bPoseChannel *pchan, + const float delta_mat[4][4], + float r_new_arm_mat[4][4]) +{ + EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name); + float delta[3], new_tail[3], premat[3][3], new_pose[4][4]; + + /* Current orientation matrix. */ + sub_v3_v3v3(delta, curbone->tail, curbone->head); + vec_roll_to_mat3(delta, curbone->roll, premat); + + /* New location and orientation. */ + mul_m4_m4m3(new_pose, delta_mat, premat); + mul_v3_m4v3(new_pose[3], delta_mat, curbone->head); + mul_v3_m4v3(new_tail, delta_mat, curbone->tail); + + applyarmature_set_edit_position(curbone, new_pose, new_tail, r_new_arm_mat); +} + +/* Data about parent position for Apply To Selected mode. */ +typedef struct ApplyArmature_ParentState { + Bone *bone; + + /* New rest position of the bone with scale included. */ + float new_rest_mat[4][4]; + /* New arm_mat of the bone == new_rest_mat without scale. */ + float new_arm_mat[4][4]; +} ApplyArmature_ParentState; + +/* Recursive walk for Apply To Selected mode; pstate NULL unless child of an applied bone. */ +static void applyarmature_process_selected_rec(bArmature *arm, + bPose *pose, + bPose *pose_eval, + Bone *bone, + ListBase *selected, + ApplyArmature_ParentState *pstate) +{ + bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name); + const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(pose_eval, bone->name); + + if (!pchan || !pchan_eval) + return; + + ApplyArmature_ParentState new_pstate = {.bone = bone}; + + if (BLI_findptr(selected, pchan, offsetof(CollectionPointerLink, ptr.data))) { + /* SELECTED BONE: Snap to final pose transform minus unapplied parent effects. + * + * I.e. bone position with accumulated parent effects but no local + * transformation will match the original final pose_mat. + * + * Pose channels are reset as expected. + */ + EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name); + BoneParentTransform invparent; + float new_tail[3]; + + if (pchan->parent) { + BoneParentTransform old_bpt, new_bpt; + float offs_bone[4][4]; + + /* Parent effects on the bone transform that have to be removed. */ + BKE_bone_offset_matrix_get(bone, offs_bone); + BKE_bone_parent_transform_calc_from_matrices( + bone->flag, offs_bone, bone->parent->arm_mat, pchan_eval->parent->pose_mat, &old_bpt); + + /* Applied parent effects that have to be kept, if any. */ + float(*new_parent_pose)[4] = pstate ? pstate->new_rest_mat : bone->parent->arm_mat; + BKE_bone_parent_transform_calc_from_matrices( + bone->flag, offs_bone, bone->parent->arm_mat, new_parent_pose, &new_bpt); + + BKE_bone_parent_transform_invert(&old_bpt); + BKE_bone_parent_transform_combine(&new_bpt, &old_bpt, &invparent); + } + else { + BKE_bone_parent_transform_clear(&invparent); + } + + /* Apply change without inherited unapplied parent transformations. */ + BKE_bone_parent_transform_apply(&invparent, pchan_eval->pose_mat, new_pstate.new_rest_mat); + + copy_v3_fl3(new_tail, 0.0, bone->length, 0.0); + mul_m4_v3(new_pstate.new_rest_mat, new_tail); + + applyarmature_set_edit_position( + curbone, new_pstate.new_rest_mat, new_tail, new_pstate.new_arm_mat); + applyarmature_transfer_properties(curbone, pchan, pchan_eval); + + pstate = &new_pstate; + } + else if (pstate) { + /* UNSELECTED CHILD OF SELECTED: Include applied parent effects. + * + * The inherited transform of applied (selected) bones is baked + * into the rest pose so that the final bone position doesn't + * change. + * + * Pose channels are not changed, with the exception of the inherited + * applied parent scale being baked into the location pose channel. + */ + BoneParentTransform bpt; + float offs_bone[4][4], delta[4][4], old_chan_loc[3]; + + /* Include applied parent effects. */ + BKE_bone_offset_matrix_get(bone, offs_bone); + BKE_bone_parent_transform_calc_from_matrices( + bone->flag, offs_bone, pstate->bone->arm_mat, pstate->new_rest_mat, &bpt); + + unit_m4(new_pstate.new_rest_mat); + BKE_bone_parent_transform_apply(&bpt, new_pstate.new_rest_mat, new_pstate.new_rest_mat); + + /* Bone location channel in pose space relative to bone head. */ + mul_v3_mat3_m4v3(old_chan_loc, bpt.loc_mat, pchan_eval->loc); + + /* Apply the change to the rest bone position. */ + invert_m4_m4(delta, bone->arm_mat); + mul_m4_m4m4(delta, new_pstate.new_rest_mat, delta); + + applyarmature_adjust_edit_position(arm, pchan, delta, new_pstate.new_arm_mat); + + /* Location pose channel has to be updated, because it is affected + * by parent scaling, and the rest pose has no scale by definition. */ + if (!(bone->flag & BONE_CONNECTED) && !is_zero_v3(old_chan_loc)) { + float inv_parent_arm[4][4]; + + /* Compute the channel coordinate space matrices for the new rest state. */ + invert_m4_m4(inv_parent_arm, pstate->new_arm_mat); + mul_m4_m4m4(offs_bone, inv_parent_arm, new_pstate.new_arm_mat); + BKE_bone_parent_transform_calc_from_matrices( + bone->flag, offs_bone, pstate->new_arm_mat, pstate->new_arm_mat, &bpt); + + /* Re-apply the location to keep the final effect. */ + invert_m4(bpt.loc_mat); + mul_v3_mat3_m4v3(pchan->loc, bpt.loc_mat, old_chan_loc); + } + + pstate = &new_pstate; + } + + for (Bone *child = bone->childbase.first; child; child = child->next) { + applyarmature_process_selected_rec(arm, pose, pose_eval, child, selected, pstate); + } +} + /* set the current pose as the restpose */ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) { @@ -99,7 +325,9 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) bArmature *arm = BKE_armature_from_object(ob); bPose *pose; bPoseChannel *pchan; - EditBone *curbone; + ListBase selected_bones; + + const bool use_selected = RNA_boolean_get(op->ptr, "selected"); /* don't check if editmode (should be done by caller) */ if (ob->type != OB_ARMATURE) { @@ -119,80 +347,37 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) "transforms stored are relative to the old rest pose"); } + /* Find selected bones before switching to edit mode. */ + if (use_selected) { + CTX_data_selected_pose_bones(C, &selected_bones); + + if (!selected_bones.first) { + return OPERATOR_CANCELLED; + } + } + /* Get editbones of active armature to alter */ ED_armature_to_edit(arm); /* get pose of active object and move it out of posemode */ pose = ob->pose; - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); - curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name); - - /* simply copy the head/tail values from pchan over to curbone */ - copy_v3_v3(curbone->head, pchan_eval->pose_head); - copy_v3_v3(curbone->tail, pchan_eval->pose_tail); - - /* fix roll: - * 1. find auto-calculated roll value for this bone now - * 2. remove this from the 'visual' y-rotation - */ - { - float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3]; - float delta[3], eul[3]; - - /* obtain new auto y-rotation */ - sub_v3_v3v3(delta, curbone->tail, curbone->head); - vec_roll_to_mat3(delta, 0.0f, premat); - invert_m3_m3(imat, premat); - - /* get pchan 'visual' matrix */ - copy_m3_m4(pmat, pchan_eval->pose_mat); - - /* remove auto from visual and get euler rotation */ - mul_m3_m3m3(tmat, imat, pmat); - mat3_to_eul(eul, tmat); - - /* just use this euler-y as new roll value */ - curbone->roll = eul[1]; + if (use_selected) { + /* The selected only mode requires a recursive walk to handle parent-child relations. */ + for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) { + applyarmature_process_selected_rec(arm, pose, ob_eval->pose, bone, &selected_bones, NULL); } - /* combine pose and rest values for bendy bone settings, - * then clear the pchan values (so we don't get a double-up) - */ - if (pchan->bone->segments > 1) { - /* combine rest/pose values */ - curbone->curve_in_x += pchan_eval->curve_in_x; - curbone->curve_in_y += pchan_eval->curve_in_y; - curbone->curve_out_x += pchan_eval->curve_out_x; - curbone->curve_out_y += pchan_eval->curve_out_y; - curbone->roll1 += pchan_eval->roll1; - curbone->roll2 += pchan_eval->roll2; - curbone->ease1 += pchan_eval->ease1; - curbone->ease2 += pchan_eval->ease2; - curbone->scale_in_x *= pchan_eval->scale_in_x; - curbone->scale_in_y *= pchan_eval->scale_in_y; - curbone->scale_out_x *= pchan_eval->scale_out_x; - curbone->scale_out_y *= pchan_eval->scale_out_y; - - /* reset pose values */ - pchan->curve_in_x = pchan->curve_out_x = 0.0f; - pchan->curve_in_y = pchan->curve_out_y = 0.0f; - pchan->roll1 = pchan->roll2 = 0.0f; - pchan->ease1 = pchan->ease2 = 0.0f; - pchan->scale_in_x = pchan->scale_in_y = 1.0f; - pchan->scale_out_x = pchan->scale_out_y = 1.0f; - } - - /* clear transform values for pchan */ - zero_v3(pchan->loc); - zero_v3(pchan->eul); - unit_qt(pchan->quat); - unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); - pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f; + BLI_freelistN(&selected_bones); + } + else { + for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); + EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name); - /* set anim lock */ - curbone->flag |= BONE_UNKEYED; + applyarmature_set_edit_position(curbone, pchan_eval->pose_mat, pchan_eval->pose_tail, NULL); + applyarmature_transfer_properties(curbone, pchan, pchan_eval); + } } /* convert editbones back to bones, and then free the edit-data */ @@ -212,6 +397,17 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static void apply_armature_pose2bones_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + uiItemR(layout, &ptr, "selected", 0, NULL, ICON_NONE); +} + void POSE_OT_armature_apply(wmOperatorType *ot) { /* identifiers */ @@ -222,9 +418,16 @@ void POSE_OT_armature_apply(wmOperatorType *ot) /* callbacks */ ot->exec = apply_armature_pose2bones_exec; ot->poll = ED_operator_posemode; + ot->ui = apply_armature_pose2bones_ui; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; + + RNA_def_boolean(ot->srna, + "selected", + false, + "Selected Only", + "Only apply the selected bones (with propagation to children)"); } /* set the current pose as the restpose */ @@ -1022,7 +1225,6 @@ static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op) for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->prop) { IDP_FreeProperty(pchan->prop); - MEM_freeN(pchan->prop); } } diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index a1f763ac57d..fbaf2c896d0 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -203,7 +203,6 @@ void poseAnim_mapping_free(ListBase *pfLinks) /* free custom properties */ if (pfl->oldprops) { IDP_FreeProperty(pfl->oldprops); - MEM_freeN(pfl->oldprops); } /* free list of F-Curve reference links */ diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index a787b45c13c..1e40ba2f19b 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -2584,33 +2584,42 @@ void CURVE_OT_switch_direction(wmOperatorType *ot) static int set_goal_weight_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; - BezTriple *bezt; - BPoint *bp; - float weight = RNA_float_get(op->ptr, "weight"); - int a; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->bezt) { - for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { - if (bezt->f2 & SELECT) { - bezt->weight = weight; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + float weight = RNA_float_get(op->ptr, "weight"); + int a; + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->bezt) { + for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { + if (bezt->f2 & SELECT) { + bezt->weight = weight; + } } } - } - else if (nu->bp) { - for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { - if (bp->f1 & SELECT) { - bp->weight = weight; + else if (nu->bp) { + for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { + if (bp->f1 & SELECT) { + bp->weight = weight; + } } } } + + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); } - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -2638,33 +2647,42 @@ void CURVE_OT_spline_weight_set(wmOperatorType *ot) static int set_radius_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; - BezTriple *bezt; - BPoint *bp; - float radius = RNA_float_get(op->ptr, "radius"); - int a; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->bezt) { - for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { - if (bezt->f2 & SELECT) { - bezt->radius = radius; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + float radius = RNA_float_get(op->ptr, "radius"); + int a; + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->bezt) { + for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { + if (bezt->f2 & SELECT) { + bezt->radius = radius; + } } } - } - else if (nu->bp) { - for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { - if (bp->f1 & SELECT) { - bp->radius = radius; + else if (nu->bp) { + for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { + if (bp->f1 & SELECT) { + bp->radius = radius; + } } } } + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -2743,81 +2761,90 @@ static void smooth_single_bp(BPoint *bp, static int smooth_exec(bContext *C, wmOperator *UNUSED(op)) { const float factor = 1.0f / 6.0f; - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - int a, a_end; - bool changed = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->bezt) { - /* duplicate the curve to use in weight calculation */ - const BezTriple *bezt_orig = MEM_dupallocN(nu->bezt); - BezTriple *bezt; - changed = false; + int a, a_end; + bool changed = false; - /* check whether its cyclic or not, and set initial & final conditions */ - if (nu->flagu & CU_NURB_CYCLIC) { - a = 0; - a_end = nu->pntsu; - } - else { - a = 1; - a_end = nu->pntsu - 1; - } + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->bezt) { + /* duplicate the curve to use in weight calculation */ + const BezTriple *bezt_orig = MEM_dupallocN(nu->bezt); + BezTriple *bezt; + changed = false; - /* for all the curve points */ - for (; a < a_end; a++) { - /* respect selection */ - bezt = &nu->bezt[a]; - if (bezt->f2 & SELECT) { - const BezTriple *bezt_orig_prev, *bezt_orig_next; + /* check whether its cyclic or not, and set initial & final conditions */ + if (nu->flagu & CU_NURB_CYCLIC) { + a = 0; + a_end = nu->pntsu; + } + else { + a = 1; + a_end = nu->pntsu - 1; + } - bezt_orig_prev = &bezt_orig[mod_i(a - 1, nu->pntsu)]; - bezt_orig_next = &bezt_orig[mod_i(a + 1, nu->pntsu)]; + /* for all the curve points */ + for (; a < a_end; a++) { + /* respect selection */ + bezt = &nu->bezt[a]; + if (bezt->f2 & SELECT) { + const BezTriple *bezt_orig_prev, *bezt_orig_next; - smooth_single_bezt(bezt, bezt_orig_prev, bezt_orig_next, factor); + bezt_orig_prev = &bezt_orig[mod_i(a - 1, nu->pntsu)]; + bezt_orig_next = &bezt_orig[mod_i(a + 1, nu->pntsu)]; - changed = true; + smooth_single_bezt(bezt, bezt_orig_prev, bezt_orig_next, factor); + + changed = true; + } + } + MEM_freeN((void *)bezt_orig); + if (changed) { + BKE_nurb_handles_calc(nu); } } - MEM_freeN((void *)bezt_orig); - if (changed) { - BKE_nurb_handles_calc(nu); - } - } - else if (nu->bp) { - /* Same as above, keep these the same! */ - const BPoint *bp_orig = MEM_dupallocN(nu->bp); - BPoint *bp; + else if (nu->bp) { + /* Same as above, keep these the same! */ + const BPoint *bp_orig = MEM_dupallocN(nu->bp); + BPoint *bp; - if (nu->flagu & CU_NURB_CYCLIC) { - a = 0; - a_end = nu->pntsu; - } - else { - a = 1; - a_end = nu->pntsu - 1; - } + if (nu->flagu & CU_NURB_CYCLIC) { + a = 0; + a_end = nu->pntsu; + } + else { + a = 1; + a_end = nu->pntsu - 1; + } - for (; a < a_end; a++) { - bp = &nu->bp[a]; - if (bp->f1 & SELECT) { - const BPoint *bp_orig_prev, *bp_orig_next; + for (; a < a_end; a++) { + bp = &nu->bp[a]; + if (bp->f1 & SELECT) { + const BPoint *bp_orig_prev, *bp_orig_next; - bp_orig_prev = &bp_orig[mod_i(a - 1, nu->pntsu)]; - bp_orig_next = &bp_orig[mod_i(a + 1, nu->pntsu)]; + bp_orig_prev = &bp_orig[mod_i(a - 1, nu->pntsu)]; + bp_orig_next = &bp_orig[mod_i(a + 1, nu->pntsu)]; - smooth_single_bp(bp, bp_orig_prev, bp_orig_next, factor); + smooth_single_bp(bp, bp_orig_prev, bp_orig_next, factor); + } } + MEM_freeN((void *)bp_orig); } - MEM_freeN((void *)bp_orig); } + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3023,13 +3050,22 @@ static void curve_smooth_value(ListBase *editnurb, const int bezt_offsetof, cons static int curve_smooth_weight_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); - curve_smooth_value(editnurb, offsetof(BezTriple, weight), offsetof(BPoint, weight)); + curve_smooth_value(editnurb, offsetof(BezTriple, weight), offsetof(BPoint, weight)); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3051,13 +3087,22 @@ void CURVE_OT_smooth_weight(wmOperatorType *ot) static int curve_smooth_radius_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); + + curve_smooth_value(editnurb, offsetof(BezTriple, radius), offsetof(BPoint, radius)); - curve_smooth_value(editnurb, offsetof(BezTriple, radius), offsetof(BPoint, radius)); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3079,13 +3124,22 @@ void CURVE_OT_smooth_radius(wmOperatorType *ot) static int curve_smooth_tilt_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - curve_smooth_value(editnurb, offsetof(BezTriple, tilt), offsetof(BPoint, tilt)); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); + + curve_smooth_value(editnurb, offsetof(BezTriple, tilt), offsetof(BPoint, tilt)); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3909,54 +3963,63 @@ static void findselectedNurbvert( static int set_spline_type_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *obedit = CTX_data_edit_object(C); - View3D *v3d = CTX_wm_view3d(C); - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; - bool changed = false; - bool changed_size = false; - const bool use_handles = RNA_boolean_get(op->ptr, "use_handles"); - const int type = RNA_enum_get(op->ptr, "type"); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + int ret_value = OPERATOR_CANCELLED; - if (type == CU_CARDINAL || type == CU_BSPLINE) { - BKE_report(op->reports, RPT_ERROR, "Not yet implemented"); - return OPERATOR_CANCELLED; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + Main *bmain = CTX_data_main(C); + View3D *v3d = CTX_wm_view3d(C); + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + bool changed = false; + bool changed_size = false; + const bool use_handles = RNA_boolean_get(op->ptr, "use_handles"); + const int type = RNA_enum_get(op->ptr, "type"); - for (nu = editnurb->first; nu; nu = nu->next) { - if (ED_curve_nurb_select_check(v3d, nu)) { - const int pntsu_prev = nu->pntsu; - if (BKE_nurb_type_convert(nu, type, use_handles)) { - changed = true; - if (pntsu_prev != nu->pntsu) { - changed_size = true; + if (type == CU_CARDINAL || type == CU_BSPLINE) { + BKE_report(op->reports, RPT_ERROR, "Not yet implemented"); + continue; + } + + for (nu = editnurb->first; nu; nu = nu->next) { + if (ED_curve_nurb_select_check(v3d, nu)) { + const int pntsu_prev = nu->pntsu; + if (BKE_nurb_type_convert(nu, type, use_handles)) { + changed = true; + if (pntsu_prev != nu->pntsu) { + changed_size = true; + } + } + else { + BKE_report(op->reports, RPT_ERROR, "No conversion possible"); } - } - else { - BKE_report(op->reports, RPT_ERROR, "No conversion possible"); } } - } - if (changed) { - if (ED_curve_updateAnimPaths(bmain, obedit->data)) { - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); - } + if (changed) { + if (ED_curve_updateAnimPaths(bmain, obedit->data)) { + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + } - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - if (changed_size) { - Curve *cu = obedit->data; - cu->actvert = CU_ACT_NONE; - } + if (changed_size) { + Curve *cu = obedit->data; + cu->actvert = CU_ACT_NONE; + } - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; + ret_value = OPERATOR_FINISHED; + } } + + MEM_freeN(objects); + + return ret_value; } void CURVE_OT_spline_type_set(wmOperatorType *ot) @@ -5551,6 +5614,8 @@ static int add_vertex_exec(bContext *C, wmOperator *op) } WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + DEG_id_tag_update(obedit->data, 0); return OPERATOR_FINISHED; @@ -6745,31 +6810,41 @@ void CURVE_OT_decimate(wmOperatorType *ot) static int shade_smooth_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); View3D *v3d = CTX_wm_view3d(C); - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; + ViewLayer *view_layer = CTX_data_view_layer(C); int clear = (STREQ(op->idname, "CURVE_OT_shade_flat")); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + int ret_value = OPERATOR_CANCELLED; - if (obedit->type != OB_CURVE) { - return OPERATOR_CANCELLED; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); - for (nu = editnurb->first; nu; nu = nu->next) { - if (ED_curve_nurb_select_check(v3d, nu)) { - if (!clear) { - nu->flag |= CU_SMOOTH; - } - else { - nu->flag &= ~CU_SMOOTH; + if (obedit->type != OB_CURVE) { + continue; + } + + for (Nurb *nu = editnurb->first; nu; nu = nu->next) { + if (ED_curve_nurb_select_check(v3d, nu)) { + if (!clear) { + nu->flag |= CU_SMOOTH; + } + else { + nu->flag &= ~CU_SMOOTH; + } } } + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + ret_value = OPERATOR_FINISHED; } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); - return OPERATOR_FINISHED; + return ret_value; } void CURVE_OT_shade_smooth(wmOperatorType *ot) @@ -7024,7 +7099,7 @@ static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op)) int a; if (object->runtime.curve_cache == NULL) { - BKE_displist_make_curveTypes(depsgraph, scene, object, false, false, NULL); + BKE_displist_make_curveTypes(depsgraph, scene, object, false, false); } INIT_MINMAX(min, max); diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index d1b1f43d8dd..ffbfb692ca9 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -2007,7 +2007,7 @@ static int font_open_exec(bContext *C, wmOperator *op) id_us_min(&font->id); RNA_id_pointer_create(&font->id, &idptr); - RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); + RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); RNA_property_update(C, &pprop->ptr, pprop->prop); } @@ -2090,7 +2090,7 @@ static int font_unlink_exec(bContext *C, wmOperator *op) builtin_font = BKE_vfont_builtin_get(); RNA_id_pointer_create(&builtin_font->id, &idptr); - RNA_property_pointer_set(&pprop.ptr, pprop.prop, idptr); + RNA_property_pointer_set(&pprop.ptr, pprop.prop, idptr, NULL); RNA_property_update(C, &pprop.ptr, pprop.prop); return OPERATOR_FINISHED; diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 316ad3f91d6..d2d0095bdb2 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -569,9 +569,9 @@ set(ICON_NAMES loop_forwards back forward + file_cache file_volume - alembic - volume + file_3d file_hidden file_backup disk_drive diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 463c2144276..9ef0657ae83 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -314,7 +314,7 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op) BKE_paint_ensure(ts, (Paint **)&ts->gp_paint); Paint *paint = &ts->gp_paint->paint; /* if not exist, create a new one */ - if (paint->brush == NULL) { + if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { BKE_brush_gpencil_presets(C); } BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint); diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 96f405fab2f..bf15b846bb6 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -401,7 +401,8 @@ static bool gp_render_offscreen(tGPDfill *tgpf) glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - ED_view3d_update_viewmat(tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar, NULL, winmat, NULL); + ED_view3d_update_viewmat( + tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar, NULL, winmat, NULL, true); /* set for opengl */ GPU_matrix_projection_set(tgpf->rv3d->winmat); GPU_matrix_set(tgpf->rv3d->viewmat); diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 9d3c2a6e271..93d8555e014 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -110,7 +110,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo Paint *paint = &ts->gp_paint->paint; /* if not exist, create a new one */ - if (paint->brush == NULL) { + if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { /* create new brushes */ BKE_brush_gpencil_presets(C); } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index b1b29356060..cd1ebc91fbb 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1819,7 +1819,7 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p) Paint *paint = &ts->gp_paint->paint; bool changed = false; /* if not exist, create a new one */ - if (paint->brush == NULL) { + if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { /* create new brushes */ BKE_brush_gpencil_presets(C); changed = true; diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 08fee2bb393..bff17bf5078 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -314,7 +314,7 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi) /* if brush doesn't exist, create a new one */ Paint *paint = &ts->gp_paint->paint; /* if not exist, create a new one */ - if (paint->brush == NULL) { + if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { /* create new brushes */ BKE_brush_gpencil_presets(C); } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 129bd01574c..93a80f0fcf8 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -1387,7 +1387,7 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob) BKE_paint_ensure(ts, (Paint **)&ts->gp_paint); Paint *paint = &ts->gp_paint->paint; /* if not exist, create a new one */ - if (paint->brush == NULL) { + if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { /* create new brushes */ BKE_brush_gpencil_presets(C); } diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index d947322f708..cd68981dee3 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -403,11 +403,14 @@ typedef enum eAnimFilter_Flags { /* -------------- Channel Defines -------------- */ /* channel heights */ -#define ACHANNEL_FIRST(ac) (-0.8f * (ac)->yscale_fac * U.widget_unit) +#define ACHANNEL_FIRST_TOP(ac) \ + (UI_view2d_scale_get_y(&(ac)->ar->v2d) * -UI_SCRUBBING_MARGIN_Y - ACHANNEL_SKIP) #define ACHANNEL_HEIGHT(ac) (0.8f * (ac)->yscale_fac * U.widget_unit) -#define ACHANNEL_HEIGHT_HALF(ac) (0.4f * (ac)->yscale_fac * U.widget_unit) #define ACHANNEL_SKIP (0.1f * U.widget_unit) #define ACHANNEL_STEP(ac) (ACHANNEL_HEIGHT(ac) + ACHANNEL_SKIP) +/* Additional offset to give some room at the end. */ +#define ACHANNEL_TOT_HEIGHT(ac, item_amount) \ + (-ACHANNEL_FIRST_TOP(ac) + ACHANNEL_STEP(ac) * (item_amount + 1)) /* channel widths */ #define ACHANNEL_NAMEWIDTH (10 * U.widget_unit) @@ -418,13 +421,15 @@ typedef enum eAnimFilter_Flags { /* -------------- NLA Channel Defines -------------- */ /* NLA channel heights */ -#define NLACHANNEL_FIRST (-0.8f * U.widget_unit) +#define NLACHANNEL_FIRST_TOP(ac) \ + (UI_view2d_scale_get_y(&(ac)->ar->v2d) * -UI_SCRUBBING_MARGIN_Y - NLACHANNEL_SKIP) #define NLACHANNEL_HEIGHT(snla) \ ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.8f * U.widget_unit) : (1.2f * U.widget_unit)) -#define NLACHANNEL_HEIGHT_HALF(snla) \ - ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.4f * U.widget_unit) : (0.6f * U.widget_unit)) #define NLACHANNEL_SKIP (0.1f * U.widget_unit) #define NLACHANNEL_STEP(snla) (NLACHANNEL_HEIGHT(snla) + NLACHANNEL_SKIP) +/* Additional offset to give some room at the end. */ +#define NLACHANNEL_TOT_HEIGHT(ac, item_amount) \ + (-NLACHANNEL_FIRST_TOP(ac) + NLACHANNEL_STEP(((SpaceNla *)(ac)->sl)) * (item_amount + 1)) /* channel widths */ #define NLACHANNEL_NAMEWIDTH (10 * U.widget_unit) diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index 5bd806b3dbf..a09e1d579fd 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -28,6 +28,7 @@ struct ARegion; struct ImBuf; struct Image; struct ImageUser; +struct ReportList; struct Scene; struct SpaceImage; struct ToolSettings; @@ -110,4 +111,8 @@ void ED_image_draw_info(struct Scene *scene, bool ED_space_image_show_cache(struct SpaceImage *sima); +bool ED_image_should_save_modified(const struct bContext *C); +int ED_image_save_all_modified_info(const struct bContext *C, struct ReportList *reports); +bool ED_image_save_all_modified(const struct bContext *C, struct ReportList *reports); + #endif /* __ED_IMAGE_H__ */ diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index ce8521a1f6a..0a8304f3f8a 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -142,44 +142,55 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, void ED_mesh_undosys_type(struct UndoType *ut); /* editmesh_select.c */ +struct EDBMSelectID_Context; +struct EDBMSelectID_Context *EDBM_select_id_context_create(struct ViewContext *vc, + struct Base **bases, + const uint bases_len, + short select_mode); +void EDBM_select_id_context_destroy(struct EDBMSelectID_Context *sel_id_ctx); +struct BMElem *EDBM_select_id_bm_elem_get(struct EDBMSelectID_Context *sel_id_ctx, + const uint sel_id, + uint *r_base_index); + +uint EDBM_select_id_context_offset_for_object_elem(const struct EDBMSelectID_Context *sel_id_ctx, + int base_index, + char htype); + +uint EDBM_select_id_context_elem_len(const struct EDBMSelectID_Context *sel_id_ctx); + void EDBM_select_mirrored( struct BMEditMesh *em, const int axis, const bool extend, int *r_totmirr, int *r_totfail); void EDBM_automerge(struct Scene *scene, struct Object *ob, bool update, const char hflag); -bool EDBM_backbuf_border_init( - struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax); -bool EDBM_backbuf_check(unsigned int index); -void EDBM_backbuf_free(void); - -bool EDBM_backbuf_border_mask_init(struct ViewContext *vc, - const int mcords[][2], - short tot, - short xmin, - short ymin, - short xmax, - short ymax); -bool EDBM_backbuf_circle_init(struct ViewContext *vc, short xs, short ys, short rads); - struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc, float *r_dist, const bool use_select_bias, - bool use_cycle); + bool use_cycle, + struct Base **bases, + uint bases_len, + uint *r_base_index); struct BMVert *EDBM_vert_find_nearest(struct ViewContext *vc, float *r_dist); struct BMEdge *EDBM_edge_find_nearest_ex(struct ViewContext *vc, float *r_dist, float *r_dist_center, const bool use_select_bias, - const bool use_cycle, - struct BMEdge **r_eed_zbuf); + bool use_cycle, + struct BMEdge **r_eed_zbuf, + struct Base **bases, + uint bases_len, + uint *r_base_index); struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *r_dist); struct BMFace *EDBM_face_find_nearest_ex(struct ViewContext *vc, float *r_dist, float *r_dist_center, const bool use_select_bias, - const bool use_cycle, - struct BMFace **r_efa_zbuf); + bool use_cycle, + struct BMFace **r_efa_zbuf, + struct Base **bases, + uint bases_len, + uint *r_base_index); struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, float *r_dist); bool EDBM_unified_findnearest(struct ViewContext *vc, @@ -230,8 +241,6 @@ void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); /* rename bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len); bool EDBM_mesh_deselect_all_multi(struct bContext *C); -extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs; - /* editmesh_preselect_edgering.c */ struct EditMesh_PreSelEdgeRing; struct EditMesh_PreSelEdgeRing *EDBM_preselect_edgering_create(void); @@ -271,7 +280,6 @@ bool paintface_mouse_select(struct bContext *C, bool extend, bool deselect, bool toggle); -bool do_paintface_box_select(struct ViewContext *vc, const struct rcti *rect, int sel_op); bool paintface_deselect_all_visible(struct bContext *C, struct Object *ob, int action, diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 543b2a5781f..a7a95a4a659 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -87,9 +87,12 @@ void ED_region_panels_ex(const struct bContext *C, void ED_region_panels(const struct bContext *C, struct ARegion *ar); void ED_region_panels_layout_ex(const struct bContext *C, struct ARegion *ar, + struct ListBase *paneltypes, const char *contexts[], int contextnr, - const bool vertical); + const bool vertical, + const char *category_override); + void ED_region_panels_layout(const struct bContext *C, struct ARegion *ar); void ED_region_panels_draw(const struct bContext *C, struct ARegion *ar); @@ -142,6 +145,13 @@ void ED_area_do_mgs_subscribe_for_tool_header(const struct bContext *C, struct ScrArea *sa, struct ARegion *ar, struct wmMsgBus *mbus); +void ED_area_do_mgs_subscribe_for_tool_ui(const struct bContext *C, + struct WorkSpace *workspace, + struct Scene *scene, + struct bScreen *screen, + struct ScrArea *sa, + struct ARegion *ar, + struct wmMsgBus *mbus); /* message bus */ void ED_region_message_subscribe(struct bContext *C, @@ -433,8 +443,9 @@ enum { ED_KEYMAP_ANIMATION = (1 << 6), ED_KEYMAP_FRAMES = (1 << 7), ED_KEYMAP_HEADER = (1 << 8), - ED_KEYMAP_GPENCIL = (1 << 9), - ED_KEYMAP_FOOTER = (1 << 10), + ED_KEYMAP_FOOTER = (1 << 9), + ED_KEYMAP_GPENCIL = (1 << 10), + ED_KEYMAP_NAVBAR = (1 << 11), }; /* SCREEN_OT_space_context_cycle direction */ diff --git a/source/blender/editors/include/ED_select_buffer_utils.h b/source/blender/editors/include/ED_select_buffer_utils.h new file mode 100644 index 00000000000..af745cee676 --- /dev/null +++ b/source/blender/editors/include/ED_select_buffer_utils.h @@ -0,0 +1,43 @@ +/* + * 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_SELECT_BUFFER_UTILS_H__ +#define __ED_SELECT_BUFFER_UTILS_H__ + +struct rcti; + +/* Boolean array from selection ID's. */ +uint *ED_select_buffer_bitmap_from_rect(const uint bitmap_len, const struct rcti *rect); +uint *ED_select_buffer_bitmap_from_circle(const uint bitmap_len, + const int center[2], + const int radius); +uint *ED_select_buffer_bitmap_from_poly(const uint bitmap_len, + const int poly[][2], + const int poly_len, + const rcti *rect); + +/* Single result from selection ID's. */ +uint ED_select_buffer_sample_point(const int center[2]); +uint ED_select_buffer_find_nearest_to_point(const int center[2], + const uint id_min, + const uint id_max, + uint *dist); + +#endif /* __ED_SELECT_BUFFER_UTILS_H__ */ diff --git a/source/blender/editors/include/ED_time_scrub_ui.h b/source/blender/editors/include/ED_time_scrub_ui.h new file mode 100644 index 00000000000..a2e3098e949 --- /dev/null +++ b/source/blender/editors/include/ED_time_scrub_ui.h @@ -0,0 +1,43 @@ +/* + * 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) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup editors + */ + +#ifndef __ED_SCRUBBING_H__ +#define __ED_SCRUBBING_H__ + +struct View2DGrid; +struct bContext; +struct bDopeSheet; +struct wmEvent; + +void ED_scrubbing_draw(const struct ARegion *ar, + const struct Scene *scene, + bool display_seconds, + bool discrete_frames); + +bool ED_event_in_scrubbing_region(const struct ARegion *ar, const struct wmEvent *event); + +void ED_channel_search_draw(const struct bContext *C, + struct ARegion *ar, + struct bDopeSheet *dopesheet); + +#endif /* __ED_SCRUBBING_H__ */ diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index fd51419a3ee..5ce9133a531 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -42,6 +42,7 @@ struct GPUFX; struct GPUFXSettings; struct GPUOffScreen; struct GPUViewport; +struct ID; struct ImBuf; struct MVert; struct Main; @@ -108,8 +109,6 @@ enum eV3DCursorOrient { void ED_view3d_background_color_get(const struct Scene *scene, const struct View3D *v3d, float r_color[3]); -void ED_view3d_cursor3d_calc_mat3(const struct Scene *scene, float mat[3][3]); -void ED_view3d_cursor3d_calc_mat4(const struct Scene *scene, float mat[4][4]); void ED_view3d_cursor3d_position(struct bContext *C, const int mval[2], const bool use_depth, @@ -451,16 +450,9 @@ void ED_view3d_backbuf_depth_validate(struct ViewContext *vc); int ED_view3d_backbuf_sample_size_clamp(struct ARegion *ar, const float dist); void ED_view3d_select_id_validate(struct ViewContext *vc); -void ED_view3d_select_id_validate_with_select_mode(struct ViewContext *vc, short select_mode); -uint ED_view3d_select_id_sample(struct ViewContext *vc, int x, int y); -uint *ED_view3d_select_id_read( - struct ViewContext *vc, int xmin, int ymin, int xmax, int ymax, uint *r_buf_len); -uint *ED_view3d_select_id_read_rect(struct ViewContext *vc, - const struct rcti *rect, - uint *r_buf_len); -uint ED_view3d_select_id_read_nearest( - struct ViewContext *vc, const int mval[2], const uint min, const uint max, uint *r_dist); +uint *ED_view3d_select_id_read(int xmin, int ymin, int xmax, int ymax, uint *r_buf_len); +uint *ED_view3d_select_id_read_rect(const struct rcti *rect, uint *r_buf_len); bool ED_view3d_autodist(struct Depsgraph *depsgraph, struct ARegion *ar, @@ -572,7 +564,6 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph, bool do_sky, bool is_persp, const char *viewname, - struct GPUFXSettings *fx_settings, const bool do_color_managment, struct GPUOffScreen *ofs, struct GPUViewport *viewport); @@ -593,7 +584,6 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph, int sizex, int sizey, unsigned int flag, - unsigned int draw_flags, int alpha_mode, int samples, const char *viewname, @@ -624,7 +614,8 @@ void ED_view3d_update_viewmat(struct Depsgraph *depsgraph, struct ARegion *ar, float viewmat[4][4], float winmat[4][4], - const struct rcti *rect); + const struct rcti *rect, + bool offscreen); bool ED_view3d_quat_from_axis_view(const char view, float quat[4]); char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon); char ED_view3d_lock_view_from_index(int index); @@ -730,4 +721,9 @@ void ED_view3d_gizmo_mesh_preselect_get_active(struct bContext *C, struct Base **r_base, struct BMElem **r_ele); +/* space_view3d.c */ +void ED_view3d_buttons_region_layout_ex(const struct bContext *C, + struct ARegion *ar, + const char *category_override); + #endif /* __ED_VIEW3D_H__ */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 2f624007c98..048f30bdf26 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -24,6 +24,9 @@ /* Note: this is included multiple times with different #defines for DEF_ICON. */ /* Auto define more specific types for places that do not need the distinction. */ +#ifndef DEF_ICON_SCENE +# define DEF_ICON_SCENE DEF_ICON +#endif #ifndef DEF_ICON_COLLECTION # define DEF_ICON_COLLECTION DEF_ICON #endif @@ -66,7 +69,7 @@ DEF_ICON(COLLAPSEMENU) DEF_ICON(X) DEF_ICON(DUPLICATE) DEF_ICON(TRASH) -DEF_ICON_BLANK(76) +DEF_ICON(COLLECTION_NEW) DEF_ICON_BLANK(77) DEF_ICON(NODE) DEF_ICON(NODE_SEL) @@ -93,8 +96,8 @@ DEF_ICON(PINNED) DEF_ICON(SCREEN_BACK) DEF_ICON(RIGHTARROW) DEF_ICON(DOWNARROW_HLT) -DEF_ICON_BLANK(103) -DEF_ICON_BLANK(104) +DEF_ICON(FCURVE_SNAPSHOT) +DEF_ICON(OBJECT_HIDDEN) DEF_ICON_BLANK(105) DEF_ICON_BLANK(106) DEF_ICON(PLUGIN) @@ -133,18 +136,18 @@ DEF_ICON_SHADING(MATERIAL) DEF_ICON_SHADING(TEXTURE) DEF_ICON(ANIM) DEF_ICON_SHADING(WORLD) -DEF_ICON(SCENE) -DEF_ICON(OUTPUT) +DEF_ICON_SCENE(SCENE) +DEF_ICON_SCENE(OUTPUT) DEF_ICON_BLANK(145) DEF_ICON_BLANK(146) DEF_ICON(SCRIPT) DEF_ICON_MODIFIER(PARTICLES) -DEF_ICON(PHYSICS) -DEF_ICON(SPEAKER) +DEF_ICON_MODIFIER(PHYSICS) +DEF_ICON_OBJECT_DATA(SPEAKER) DEF_ICON_BLANK(151) -DEF_ICON(TOOL_SETTINGS) -DEF_ICON(SHADERFX) -DEF_ICON(MODIFIER) +DEF_ICON_SCENE(TOOL_SETTINGS) +DEF_ICON_MODIFIER(SHADERFX) +DEF_ICON_MODIFIER(MODIFIER) DEF_ICON_BLANK(155) DEF_ICON_BLANK(156) DEF_ICON_BLANK(157) @@ -163,7 +166,7 @@ DEF_ICON(FILEBROWSER) DEF_ICON(IMAGE) DEF_ICON(INFO) DEF_ICON(SEQUENCE) -DEF_ICON(TEXT) +DEF_ICON_OBJECT_DATA(TEXT) DEF_ICON_BLANK(174) DEF_ICON(SOUND) DEF_ICON(ACTION) @@ -211,27 +214,27 @@ DEF_ICON(TRACKING_REFINE_FORWARDS) DEF_ICON_BLANK(77b) /* DATA */ -DEF_ICON(SCENE_DATA) -DEF_ICON(RENDERLAYERS) +DEF_ICON_SCENE(SCENE_DATA) +DEF_ICON_SCENE(RENDERLAYERS) DEF_ICON_SHADING(WORLD_DATA) -DEF_ICON(OBJECT_DATA) -DEF_ICON(MESH_DATA) -DEF_ICON(CURVE_DATA) -DEF_ICON(META_DATA) -DEF_ICON(LATTICE_DATA) -DEF_ICON_SHADING(LIGHT_DATA) +DEF_ICON_OBJECT(OBJECT_DATA) +DEF_ICON_OBJECT_DATA(MESH_DATA) +DEF_ICON_OBJECT_DATA(CURVE_DATA) +DEF_ICON_OBJECT_DATA(META_DATA) +DEF_ICON_OBJECT_DATA(LATTICE_DATA) +DEF_ICON_OBJECT_DATA(LIGHT_DATA) DEF_ICON_SHADING(MATERIAL_DATA) DEF_ICON_SHADING(TEXTURE_DATA) DEF_ICON(ANIM_DATA) -DEF_ICON(CAMERA_DATA) -DEF_ICON(PARTICLE_DATA) +DEF_ICON_OBJECT_DATA(CAMERA_DATA) +DEF_ICON_OBJECT_DATA(PARTICLE_DATA) DEF_ICON(LIBRARY_DATA_DIRECT) DEF_ICON_COLLECTION(GROUP) -DEF_ICON(ARMATURE_DATA) +DEF_ICON_OBJECT_DATA(ARMATURE_DATA) DEF_ICON(COMMUNITY) -DEF_ICON(BONE_DATA) +DEF_ICON_OBJECT_DATA(BONE_DATA) DEF_ICON_MODIFIER(CONSTRAINT) -DEF_ICON(SHAPEKEY_DATA) +DEF_ICON_OBJECT_DATA(SHAPEKEY_DATA) DEF_ICON_MODIFIER(CONSTRAINT_BONE) DEF_ICON(CAMERA_STEREO) DEF_ICON(PACKAGE) @@ -243,10 +246,10 @@ DEF_ICON_SHADING(BRUSH_DATA) DEF_ICON_SHADING(IMAGE_DATA) DEF_ICON(FILE) DEF_ICON(FCURVE) -DEF_ICON(FONT_DATA) -DEF_ICON(RENDER_RESULT) -DEF_ICON(SURFACE_DATA) -DEF_ICON(EMPTY_DATA) +DEF_ICON_OBJECT_DATA(FONT_DATA) +DEF_ICON_SCENE(RENDER_RESULT) +DEF_ICON_OBJECT_DATA(SURFACE_DATA) +DEF_ICON_OBJECT_DATA(EMPTY_DATA) DEF_ICON(PRESET) DEF_ICON(RENDER_ANIMATION) DEF_ICON(RENDER_STILL) @@ -254,7 +257,7 @@ DEF_ICON(LIBRARY_DATA_BROKEN) DEF_ICON(BOIDS) DEF_ICON(STRANDS) DEF_ICON(LIBRARY_DATA_INDIRECT) -DEF_ICON(GREASEPENCIL) +DEF_ICON_OBJECT_DATA(GREASEPENCIL) DEF_ICON_SHADING(LINE_DATA) DEF_ICON(LIBRARY_DATA_OVERRIDE) DEF_ICON(GROUP_BONE) @@ -320,7 +323,7 @@ DEF_ICON(RESTRICT_SELECT_ON) DEF_ICON(RESTRICT_SELECT_OFF) DEF_ICON(RESTRICT_RENDER_ON) DEF_ICON(RESTRICT_RENDER_OFF) -DEF_ICON_BLANK(330) +DEF_ICON(RESTRICT_INSTANCED_OFF) /* OUTLINER */ DEF_ICON_OBJECT_DATA(OUTLINER_DATA_EMPTY) @@ -334,7 +337,7 @@ DEF_ICON_OBJECT_DATA(OUTLINER_DATA_ARMATURE) DEF_ICON_OBJECT_DATA(OUTLINER_DATA_FONT) DEF_ICON_OBJECT_DATA(OUTLINER_DATA_SURFACE) DEF_ICON_OBJECT_DATA(OUTLINER_DATA_SPEAKER) -DEF_ICON_BLANK(344) +DEF_ICON_OBJECT_DATA(OUTLINER_DATA_LIGHTPROBE) DEF_ICON_BLANK(345) DEF_ICON_OBJECT_DATA(OUTLINER_DATA_GREASEPENCIL) DEF_ICON(GP_SELECT_POINTS) @@ -348,7 +351,7 @@ DEF_ICON(ONIONSKIN_OFF) DEF_ICON(ONIONSKIN_ON) DEF_ICON(RESTRICT_VIEW_ON) DEF_ICON(RESTRICT_VIEW_OFF) -DEF_ICON_BLANK(353) +DEF_ICON(RESTRICT_INSTANCED_ON) /* PRIMITIVES */ DEF_ICON(MESH_PLANE) @@ -363,11 +366,11 @@ DEF_ICON(MESH_TORUS) DEF_ICON(MESH_CONE) DEF_ICON(MESH_CAPSULE) DEF_ICON(EMPTY_SINGLE_ARROW) -DEF_ICON_SHADING(LIGHT_POINT) -DEF_ICON_SHADING(LIGHT_SUN) -DEF_ICON_SHADING(LIGHT_SPOT) -DEF_ICON_SHADING(LIGHT_HEMI) -DEF_ICON_SHADING(LIGHT_AREA) +DEF_ICON_OBJECT_DATA(LIGHT_POINT) +DEF_ICON_OBJECT_DATA(LIGHT_SUN) +DEF_ICON_OBJECT_DATA(LIGHT_SPOT) +DEF_ICON_OBJECT_DATA(LIGHT_HEMI) +DEF_ICON_OBJECT_DATA(LIGHT_AREA) DEF_ICON(CUBE) DEF_ICON(SPHERE) DEF_ICON(CONE) @@ -393,9 +396,9 @@ DEF_ICON(CURVE_BEZCIRCLE) DEF_ICON(CURVE_NCURVE) DEF_ICON(CURVE_NCIRCLE) DEF_ICON(CURVE_PATH) -DEF_ICON_SHADING(LIGHTPROBE_CUBEMAP) -DEF_ICON_SHADING(LIGHTPROBE_PLANAR) -DEF_ICON_SHADING(LIGHTPROBE_GRID) +DEF_ICON_OBJECT_DATA(LIGHTPROBE_CUBEMAP) +DEF_ICON_OBJECT_DATA(LIGHTPROBE_PLANAR) +DEF_ICON_OBJECT_DATA(LIGHTPROBE_GRID) DEF_ICON_BLANK(406) DEF_ICON_BLANK(407) DEF_ICON(COLOR_RED) @@ -422,8 +425,8 @@ DEF_ICON(FORCE_DRAG) DEF_ICON(FORCE_SMOKEFLOW) DEF_ICON_BLANK(673) DEF_ICON_BLANK(674) -DEF_ICON_BLANK(675) -DEF_ICON_BLANK(676) +DEF_ICON(RIGID_BODY) +DEF_ICON(RIGID_BODY_CONSTRAINT) DEF_ICON_BLANK(677) DEF_ICON_BLANK(678) DEF_ICON_BLANK(679) @@ -456,11 +459,11 @@ DEF_ICON_BLANK(707) DEF_ICON_BLANK(708) DEF_ICON_BLANK(709) DEF_ICON_BLANK(710) -DEF_ICON_BLANK(711) -DEF_ICON_BLANK(712) -DEF_ICON_BLANK(713) -DEF_ICON_BLANK(714) -DEF_ICON_BLANK(715) +DEF_ICON(SELECT_SET) +DEF_ICON(SELECT_EXTEND) +DEF_ICON(SELECT_SUBTRACT) +DEF_ICON(SELECT_INTERSECT) +DEF_ICON(SELECT_DIFFERENCE) /* EMPTY */ DEF_ICON(ALIGN_LEFT) @@ -485,10 +488,10 @@ DEF_ICON_BLANK(748) DEF_ICON_BLANK(749) DEF_ICON_BLANK(750) DEF_ICON_BLANK(751) -DEF_ICON_BLANK(752) -DEF_ICON_BLANK(753) -DEF_ICON_BLANK(754) -DEF_ICON_BLANK(755) +DEF_ICON(HOLDOUT_OFF) +DEF_ICON(HOLDOUT_ON) +DEF_ICON(INDIRECT_ONLY_OFF) +DEF_ICON(INDIRECT_ONLY_ON) /* EMPTY */ DEF_ICON_BLANK(501) @@ -635,7 +638,7 @@ DEF_ICON(VERTEXSEL) DEF_ICON(EDGESEL) DEF_ICON(FACESEL) DEF_ICON_BLANK(209) -DEF_ICON_BLANK(210) +DEF_ICON(CURSOR) DEF_ICON(PIVOT_BOUNDBOX) DEF_ICON(PIVOT_CURSOR) DEF_ICON(PIVOT_INDIVIDUAL) @@ -696,8 +699,8 @@ DEF_ICON(VIS_SEL_10) DEF_ICON(VIS_SEL_01) DEF_ICON(VIS_SEL_00) DEF_ICON_BLANK(231) -DEF_ICON(AUTOMERGE_ON) DEF_ICON(AUTOMERGE_OFF) +DEF_ICON(AUTOMERGE_ON) DEF_ICON_BLANK(234) DEF_ICON(UV_VERTEXSEL) DEF_ICON(UV_EDGESEL) @@ -708,7 +711,7 @@ DEF_ICON_BLANK(240) DEF_ICON_BLANK(241) DEF_ICON_BLANK(242) DEF_ICON_BLANK(243) -DEF_ICON_BLANK(244) +DEF_ICON(GIZMO) DEF_ICON(ORIENTATION_CURSOR) DEF_ICON(NORMALS_VERTEX) DEF_ICON(NORMALS_FACE) @@ -818,9 +821,9 @@ DEF_ICON(FORWARD) DEF_ICON_BLANK(825) DEF_ICON_BLANK(826) DEF_ICON_BLANK(827) +DEF_ICON(FILE_CACHE) DEF_ICON(FILE_VOLUME) -DEF_ICON(ALEMBIC) -DEF_ICON(VOLUME) +DEF_ICON(FILE_3D) DEF_ICON(FILE_HIDDEN) DEF_ICON(FILE_BACKUP) DEF_ICON(DISK_DRIVE) @@ -1022,6 +1025,7 @@ DEF_ICON_COLOR(EVENT_RETURN) #undef DEF_ICON #undef DEF_ICON_ERROR +#undef DEF_ICON_SCENE #undef DEF_ICON_COLLECTION #undef DEF_ICON_OBJECT #undef DEF_ICON_OBJECT_DATA diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 18960853011..fddd8f09b87 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -228,6 +228,7 @@ enum { #define UI_PANEL_WIDTH 340 #define UI_COMPACT_PANEL_WIDTH 160 +#define UI_SIDEBAR_PANEL_WIDTH 220 #define UI_NAVIGATION_REGION_WIDTH UI_COMPACT_PANEL_WIDTH #define UI_NARROW_NAVIGATION_REGION_WIDTH 100 @@ -280,6 +281,9 @@ enum { /** Value is animated, but the current value differs from the animated one. */ UI_BUT_ANIMATED_CHANGED = 1 << 25, + + /* Draw the checkbox buttons inverted. */ + UI_BUT_CHECKBOX_INVERT = 1 << 26, }; /* scale fixed button widths by this to account for DPI */ @@ -594,9 +598,16 @@ struct uiLayout *UI_pie_menu_layout(struct uiPieMenu *pie); typedef uiBlock *(*uiBlockCreateFunc)(struct bContext *C, struct ARegion *ar, void *arg1); typedef void (*uiBlockCancelFunc)(struct bContext *C, void *arg1); -void UI_popup_block_invoke(struct bContext *C, uiBlockCreateFunc func, void *arg); -void UI_popup_block_invoke_ex( - struct bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext); +void UI_popup_block_invoke(struct bContext *C, + uiBlockCreateFunc func, + void *arg, + void (*arg_free)(void *arg)); +void UI_popup_block_invoke_ex(struct bContext *C, + uiBlockCreateFunc func, + void *arg, + void (*arg_free)(void *arg), + const char *opname, + int opcontext); void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, @@ -641,6 +652,7 @@ enum { UI_BLOCK_THEME_STYLE_POPUP = 1, }; void UI_block_theme_style_set(uiBlock *block, char theme_style); +char UI_block_emboss_get(uiBlock *block); void UI_block_emboss_set(uiBlock *block, char dt); void UI_block_free(const struct bContext *C, uiBlock *block); @@ -1618,7 +1630,7 @@ struct Panel *UI_panel_begin(struct ScrArea *sa, struct PanelType *pt, struct Panel *pa, bool *r_open); -void UI_panel_end(uiBlock *block, int width, int height); +void UI_panel_end(uiBlock *block, int width, int height, bool open); void UI_panels_scale(struct ARegion *ar, float new_width); void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y); int UI_panel_size_y(const struct Panel *pa); @@ -1629,6 +1641,7 @@ struct PanelCategoryDyn *UI_panel_category_find(struct ARegion *ar, const char * struct PanelCategoryStack *UI_panel_category_active_find(struct ARegion *ar, const char *idname); const char *UI_panel_category_active_get(struct ARegion *ar, bool set_fallback); void UI_panel_category_active_set(struct ARegion *ar, const char *idname); +void UI_panel_category_active_set_default(struct ARegion *ar, const char *idname); struct PanelCategoryDyn *UI_panel_category_find_mouse_over_ex(struct ARegion *ar, const int x, const int y); @@ -1702,14 +1715,28 @@ enum { UI_ITEM_O_RETURN_PROPS = 1 << 0, UI_ITEM_R_EXPAND = 1 << 1, UI_ITEM_R_SLIDER = 1 << 2, + /** + * Use for booleans, causes the button to draw with an outline (emboss), + * instead of text with a checkbox. + * This is implied when toggle buttons have an icon + * unless #UI_ITEM_R_ICON_NEVER flag is set. + */ UI_ITEM_R_TOGGLE = 1 << 3, - UI_ITEM_R_ICON_ONLY = 1 << 4, - UI_ITEM_R_EVENT = 1 << 5, - UI_ITEM_R_FULL_EVENT = 1 << 6, - UI_ITEM_R_NO_BG = 1 << 7, - UI_ITEM_R_IMMEDIATE = 1 << 8, - UI_ITEM_O_DEPRESS = 1 << 9, - UI_ITEM_R_COMPACT = 1 << 10, + /** + * Don't attempt to use an icon when the icon is set to #ICON_NONE. + * + * Use for boolean's, causes the buttons to always show as a checkbox + * even when there is an icon (which would normally show the button as a toggle). + */ + UI_ITEM_R_ICON_NEVER = 1 << 4, + UI_ITEM_R_ICON_ONLY = 1 << 5, + UI_ITEM_R_EVENT = 1 << 6, + UI_ITEM_R_FULL_EVENT = 1 << 7, + UI_ITEM_R_NO_BG = 1 << 8, + UI_ITEM_R_IMMEDIATE = 1 << 9, + UI_ITEM_O_DEPRESS = 1 << 10, + UI_ITEM_R_COMPACT = 1 << 11, + UI_ITEM_R_CHECKBOX_INVERT = 1 << 12, }; #define UI_HEADER_OFFSET ((void)0, 0.4f * UI_UNIT_X) diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index 5666421c27f..1f15fa3bd4d 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -52,8 +52,11 @@ typedef struct IconFile { * Resizable Icons for Blender */ void UI_icons_init(void); +void UI_icons_reload_internal_textures(void); + int UI_icon_get_width(int icon_id); int UI_icon_get_height(int icon_id); +bool UI_icon_get_theme_color(int icon_id, unsigned char color[4]); void UI_id_icon_render(const struct bContext *C, struct Scene *scene, @@ -64,16 +67,17 @@ int UI_preview_render_size(enum eIconSizes size); void UI_icon_draw(float x, float y, int icon_id); void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha); -void UI_icon_draw_preview(float x, float y, int icon_id); -void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect); -void UI_icon_draw_preview_aspect_size( - float x, float y, int icon_id, float aspect, float alpha, int size); - -void UI_icon_draw_aspect( - float x, float y, int icon_id, float aspect, float alpha, const char mono_color[4]); -void UI_icon_draw_aspect_color( - float x, float y, int icon_id, float aspect, const float rgb[3], const char mono_color[4]); -void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha); +void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size); + +void UI_icon_draw_ex(float x, + float y, + int icon_id, + float aspect, + float alpha, + float desaturate, + const char mono_color[4], + const bool mono_border); + void UI_icon_draw_desaturate(float x, float y, int icon_id, @@ -81,6 +85,7 @@ void UI_icon_draw_desaturate(float x, float alpha, float desaturate, const char mono_color[4]); + void UI_icons_free(void); void UI_icons_free_drawinfo(void *drawinfo); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index af94889a1bb..6dc632921ad 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -105,6 +105,7 @@ typedef enum ThemeColorID { TH_FACE_DOT, TH_FACEDOT_SIZE, TH_CFRAME, + TH_SCRUBBING_BACKGROUND, TH_TIME_KEYFRAME, TH_TIME_GP_KEYFRAME, TH_NURB_ULINE, @@ -254,6 +255,10 @@ typedef enum ThemeColorID { TH_MATCH, /* highlight color for search matches */ TH_SELECT_HIGHLIGHT, /* highlight color for selected outliner item */ + TH_SELECTED_OBJECT, /* selected object color for outliner */ + TH_ACTIVE_OBJECT, /* active object color for outliner */ + TH_EDITED_OBJECT, /* edited object color for outliner */ + TH_ROW_ALTERNATE, /* overlay on every other row */ TH_SKIN_ROOT, @@ -261,12 +266,15 @@ typedef enum ThemeColorID { TH_ANIM_INACTIVE, /* no active action */ TH_ANIM_PREVIEW_RANGE, /* preview range overlay */ + TH_ICON_SCENE, TH_ICON_COLLECTION, TH_ICON_OBJECT, TH_ICON_OBJECT_DATA, TH_ICON_MODIFIER, TH_ICON_SHADING, + TH_SCROLL_TEXT, + TH_NLA_TWEAK, /* 'tweaking' track in NLA */ TH_NLA_TWEAK_DUPLI, /* error/warning flag for other strips referencing dupli strip */ @@ -380,7 +388,7 @@ void UI_GetThemeColorType3ubv(int colorid, int spacetype, unsigned char col[3]); void UI_GetThemeColorType4ubv(int colorid, int spacetype, unsigned char col[4]); // get theme color for coloring monochrome icons -bool UI_GetIconThemeColor4fv(int colorid, float col[4]); +bool UI_GetIconThemeColor4ubv(int colorid, unsigned char col[4]); // shade a 3 byte color (same as UI_GetColorPtrBlendShade3ubv with 0.0 factor) void UI_GetColorPtrShade3ubv(const unsigned char cp1[3], unsigned char col[3], int offset); diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 07dbb49ac07..d03d4b1b4f5 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -63,9 +63,9 @@ enum eView2D_CommonViewTypes { /* scroller area */ #define V2D_SCROLL_HEIGHT (0.45f * U.widget_unit) #define V2D_SCROLL_WIDTH (0.45f * U.widget_unit) -/* For scrollers with scale markings (text written onto them) */ -#define V2D_SCROLL_HEIGHT_TEXT (0.79f * U.widget_unit) -#define V2D_SCROLL_WIDTH_TEXT (0.79f * U.widget_unit) +/* For scrollers with scale handlers */ +#define V2D_SCROLL_HEIGHT_HANDLES (0.6f * U.widget_unit) +#define V2D_SCROLL_WIDTH_HANDLES (0.6f * U.widget_unit) /* scroller 'handles' hotspot radius for mouse */ #define V2D_SCROLLER_HANDLE_SIZE (0.6f * U.widget_unit) @@ -152,30 +152,24 @@ float UI_view2d_grid_resolution_y__values(const struct View2D *v2d); /* scale indicator text drawing */ void UI_view2d_draw_scale_y__values(const struct ARegion *ar, const struct View2D *v2d, - const struct rcti *rect); + const struct rcti *rect, + int colorid); void UI_view2d_draw_scale_y__block(const struct ARegion *ar, const struct View2D *v2d, - const struct rcti *rect); -void UI_view2d_draw_scale_x__values(const struct ARegion *ar, - const struct View2D *v2d, - const struct rcti *rect); -void UI_view2d_draw_scale_x__discrete_values(const struct ARegion *ar, - const struct View2D *v2d, - const struct rcti *rect); -void UI_view2d_draw_scale_x__discrete_time(const struct ARegion *ar, - const struct View2D *v2d, - const struct rcti *rect, - const struct Scene *scene); + const struct rcti *rect, + int colorid); void UI_view2d_draw_scale_x__discrete_frames_or_seconds(const struct ARegion *ar, const struct View2D *v2d, const struct rcti *rect, const struct Scene *scene, - bool display_seconds); + bool display_seconds, + int colorid); void UI_view2d_draw_scale_x__frames_or_seconds(const struct ARegion *ar, const struct View2D *v2d, const struct rcti *rect, const struct Scene *scene, - bool display_seconds); + bool display_seconds, + int colorid); /* scrollbar drawing */ View2DScrollers *UI_view2d_scrollers_calc(struct View2D *v2d, const struct rcti *mask_custom); @@ -183,16 +177,7 @@ void UI_view2d_scrollers_draw(struct View2D *v2d, View2DScrollers *scrollers); void UI_view2d_scrollers_free(View2DScrollers *scrollers); /* list view tools */ -void UI_view2d_listview_cell_to_view(struct View2D *v2d, - float columnwidth, - float rowheight, - float startx, - float starty, - int column, - int row, - struct rctf *rect); -void UI_view2d_listview_view_to_cell(struct View2D *v2d, - float columnwidth, +void UI_view2d_listview_view_to_cell(float columnwidth, float rowheight, float startx, float starty, @@ -200,15 +185,6 @@ void UI_view2d_listview_view_to_cell(struct View2D *v2d, float viewy, int *column, int *row); -void UI_view2d_listview_visible_cells(struct View2D *v2d, - float columnwidth, - float rowheight, - float startx, - float starty, - int *column_min, - int *column_max, - int *row_min, - int *row_max); /* coordinate conversion */ float UI_view2d_region_to_view_x(const struct View2D *v2d, float x); @@ -282,6 +258,8 @@ void UI_view2d_smooth_view(struct bContext *C, struct ARegion *ar, const struct rctf *cur, const int smooth_viewtx); + #define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC) +#define UI_SCRUBBING_MARGIN_Y (23 * UI_DPI_FAC) #endif /* __UI_VIEW2D_H__ */ diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 42f4b4495c3..931a4faa1c0 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1086,7 +1086,6 @@ static bool ui_but_event_operator_string_from_menu(const bContext *C, } IDP_FreeProperty(prop_menu); - MEM_freeN(prop_menu); return found; } @@ -1135,7 +1134,6 @@ static bool ui_but_event_operator_string_from_panel(const bContext *C, } IDP_FreeProperty(prop_panel); - MEM_freeN(prop_panel); return found; } @@ -1356,7 +1354,6 @@ static bool ui_but_event_property_operator_string(const bContext *C, /* cleanup */ IDP_FreeProperty(prop_path); - MEM_freeN(prop_path); if (data_path) { MEM_freeN(data_path); } @@ -1687,6 +1684,18 @@ void UI_block_draw(const bContext *C, uiBlock *block) } else if (block->panel) { bool show_background = ar->alignment != RGN_ALIGN_FLOAT; + if (show_background) { + if (block->panel->type && (block->panel->type->flag & PNL_NO_HEADER)) { + if (ar->regiontype == RGN_TYPE_TOOLS) { + /* We never want a background around active tools. */ + show_background = false; + } + else { + /* Without a header there is no background except for region overlap. */ + show_background = ar->overlap != 0; + } + } + } ui_draw_aligned_panel(&style, block, &rect, UI_panel_category_is_visible(ar), show_background); } @@ -1836,6 +1845,9 @@ int ui_but_is_pushed_ex(uiBut *but, double *value) } } + if ((but->drawflag & UI_BUT_CHECKBOX_INVERT) && (is_push != -1)) { + is_push = !((bool)is_push); + } return is_push; } int ui_but_is_pushed(uiBut *but) @@ -2763,7 +2775,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str) } else if (type == PROP_POINTER) { if (str[0] == '\0') { - RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL); + RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL, NULL); return true; } else { @@ -2779,14 +2791,14 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str) * Fact remains, using editstr as main 'reference' over whole search button thingy * is utterly weak and should be redesigned imho, but that's not a simple task. */ if (prop && RNA_property_collection_lookup_string(&ptr, prop, str, &rptr)) { - RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr); + RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr, NULL); } else if (but->func_arg2 != NULL) { RNA_pointer_create(NULL, RNA_property_pointer_type(&but->rnapoin, but->rnaprop), but->func_arg2, &rptr); - RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr); + RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr, NULL); } return true; @@ -3235,6 +3247,11 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh return block; } +char UI_block_emboss_get(uiBlock *block) +{ + return block->dt; +} + void UI_block_emboss_set(uiBlock *block, char dt) { block->dt = dt; @@ -3721,6 +3738,16 @@ void ui_def_but_icon(uiBut *but, const int icon, const int flag) } } +/** + * Avoid using this where possible since it's better not to ask for an icon in the first place. + */ +void ui_def_but_icon_clear(uiBut *but) +{ + but->icon = ICON_NONE; + but->flag &= ~UI_HAS_ICON; + but->drawflag &= ~UI_BUT_ICON_LEFT; +} + static void ui_def_but_rna__disable(uiBut *but, const char *info) { but->flag |= UI_BUT_DISABLED; diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index b9de504f3b2..4a0a19f57cf 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -82,6 +82,11 @@ void ui_but_anim_flag(uiBut *but, float cfra) if (fcu) { if (!driven) { + /* Empty curves are ignored by the animation evaluation system. */ + if (BKE_fcurve_is_empty(fcu)) { + return; + } + but->flag |= UI_BUT_ANIMATED; /* T41525 - When the active action is a NLA strip being edited, diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 748d6e6c183..d1f72519046 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -58,30 +58,89 @@ /** \name Button Context Menu * \{ */ -static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event)) +static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but) { - uiBut *but = (uiBut *)arg1; + /* Compute data path from context to property. */ + const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin); + const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin); + const char *member_id_data_path = member_id; + + if (data_path) { + member_id_data_path = BLI_sprintfN("%s.%s", member_id, data_path); + MEM_freeN((void *)data_path); + } - if (but->optype) { - char shortcut_str[128]; + const char *prop_id = RNA_property_identifier(but->rnaprop); + const char *final_data_path = BLI_sprintfN("%s.%s", member_id_data_path, prop_id); - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; + if (member_id != member_id_data_path) { + MEM_freeN((void *)member_id_data_path); + } + + /* Create ID property of data path, to pass to the operator. */ + IDProperty *prop; + IDPropertyTemplate val = {0}; + prop = IDP_New(IDP_GROUP, &val, __func__); + IDP_AddToGroup(prop, IDP_NewString(final_data_path, "data_path", strlen(final_data_path) + 1)); + + MEM_freeN((void *)final_data_path); + + return prop; +} - /* complex code to change name of button */ - if (WM_key_event_operator_string(C, - but->optype->idname, - but->opcontext, - prop, - true, - shortcut_str, - sizeof(shortcut_str))) { - ui_but_add_shortcut(but, shortcut_str, true); +static const char *shortcut_get_operator_property(bContext *C, uiBut *but, IDProperty **prop) +{ + if (but->optype) { + /* Operator */ + *prop = (but->opptr && but->opptr->data) ? IDP_CopyProperty(but->opptr->data) : NULL; + return but->optype->idname; + } + else if (but->rnaprop) { + if (RNA_property_type(but->rnaprop) == PROP_BOOLEAN) { + /* Boolean */ + *prop = shortcut_property_from_rna(C, but); + return "WM_OT_context_toggle"; } - else { - /* simply strip the shortcut */ - ui_but_add_shortcut(but, NULL, true); + else if (RNA_property_type(but->rnaprop) == PROP_ENUM) { + /* Enum */ + *prop = shortcut_property_from_rna(C, but); + return "WM_OT_context_menu_enum"; } } + + *prop = NULL; + return NULL; +} + +static void shortcut_free_operator_property(IDProperty *prop) +{ + if (prop) { + IDP_FreeProperty(prop); + } +} + +static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event)) +{ + uiBut *but = (uiBut *)arg1; + char shortcut_str[128]; + + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); + if (idname == NULL) { + return; + } + + /* complex code to change name of button */ + if (WM_key_event_operator_string( + C, idname, but->opcontext, prop, true, shortcut_str, sizeof(shortcut_str))) { + ui_but_add_shortcut(but, shortcut_str, true); + } + else { + /* simply strip the shortcut */ + ui_but_add_shortcut(but, NULL, true); + } + + shortcut_free_operator_property(prop); } static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg) @@ -94,15 +153,18 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg) PointerRNA ptr; uiLayout *layout; uiStyle *style = UI_style_get_dpi(); - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); kmi = WM_key_event_operator(C, - but->optype->idname, + idname, but->opcontext, prop, EVT_TYPE_MASK_HOTKEY_INCLUDE, EVT_TYPE_MASK_HOTKEY_EXCLUDE, &km); + U.runtime.is_dirty = true; + BLI_assert(kmi != NULL); RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr); @@ -118,6 +180,8 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg) UI_block_bounds_set_popup(block, 6, (const int[2]){-50, 26}); + shortcut_free_operator_property(prop); + return block; } @@ -135,25 +199,24 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg) PointerRNA ptr; uiLayout *layout; uiStyle *style = UI_style_get_dpi(); - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; int kmi_id; + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); /* XXX this guess_opname can potentially return a different keymap * than being found on adding later... */ - km = WM_keymap_guess_opname(C, but->optype->idname); - kmi = WM_keymap_add_item(km, but->optype->idname, AKEY, KM_PRESS, 0, 0); + km = WM_keymap_guess_opname(C, idname); + kmi = WM_keymap_add_item(km, idname, AKEY, KM_PRESS, 0, 0); kmi_id = kmi->id; - /* copy properties, prop can be NULL for reset */ - if (prop) { - prop = IDP_CopyProperty(prop); - } + /* This takes ownership of prop, or prop can be NULL for reset. */ WM_keymap_item_properties_reset(kmi, prop); /* update and get pointers again */ WM_keyconfig_update(wm); + U.runtime.is_dirty = true; - km = WM_keymap_guess_opname(C, but->optype->idname); + km = WM_keymap_guess_opname(C, idname); kmi = WM_keymap_item_find_id(km, kmi_id); RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr); @@ -171,6 +234,7 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg) #ifdef USE_KEYMAP_ADD_HACK g_kmi_id_hack = kmi_id; #endif + return block; } @@ -179,20 +243,21 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1) uiBut *but = (uiBut *)arg1; wmKeyMap *km; wmKeyMapItem *kmi; -#ifndef USE_KEYMAP_ADD_HACK - IDProperty *prop; -#endif int kmi_id; + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); + #ifdef USE_KEYMAP_ADD_HACK - km = WM_keymap_guess_opname(C, but->optype->idname); + km = WM_keymap_guess_opname(C, idname); kmi_id = g_kmi_id_hack; UNUSED_VARS(but); #else - prop = (but->opptr) ? but->opptr->data : NULL; - kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km); + kmi_id = WM_key_event_operator_id(C, idname, but->opcontext, prop, true, &km); #endif + shortcut_free_operator_property(prop); + kmi = WM_keymap_item_find_id(km, kmi_id); WM_keymap_remove_item(km, kmi); } @@ -200,7 +265,7 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1) static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) { uiBut *but = (uiBut *)arg1; - UI_popup_block_invoke(C, menu_change_shortcut, but); + UI_popup_block_invoke(C, menu_change_shortcut, but, NULL); } static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) @@ -208,10 +273,11 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) uiBut *but = (uiBut *)arg1; wmKeyMap *km; wmKeyMapItem *kmi; - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); kmi = WM_key_event_operator(C, - but->optype->idname, + idname, but->opcontext, prop, EVT_TYPE_MASK_HOTKEY_INCLUDE, @@ -220,7 +286,9 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) BLI_assert(kmi != NULL); WM_keymap_remove_item(km, kmi); + U.runtime.is_dirty = true; + shortcut_free_operator_property(prop); but_shortcut_name_func(C, but, 0); } @@ -323,6 +391,7 @@ static void popup_user_menu_add_or_replace_func(bContext *C, void *arg1, void *U { uiBut *but = arg1; bUserMenu *um = ED_screen_user_menu_ensure(C); + U.runtime.is_dirty = true; ui_but_user_menu_add(C, but, um); } @@ -330,6 +399,7 @@ static void popup_user_menu_remove_func(bContext *UNUSED(C), void *arg1, void *a { bUserMenu *um = arg1; bUserMenuItem *umi = arg2; + U.runtime.is_dirty = true; ED_screen_user_menu_item_remove(&um->items, umi); } @@ -890,16 +960,18 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) uiItemS(layout); } - /* Operator buttons */ - if (but->optype) { + /* Shortcut menu */ + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); + if (idname != NULL) { uiBlock *block = uiLayoutGetBlock(layout); uiBut *but2; - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; int w = uiLayoutGetWidth(layout); wmKeyMap *km; + /* We want to know if this op has a shortcut, be it hotkey or not. */ wmKeyMapItem *kmi = WM_key_event_operator( - C, but->optype->idname, but->opcontext, prop, EVT_TYPE_MASK_ALL, 0, &km); + C, idname, but->opcontext, prop, EVT_TYPE_MASK_ALL, 0, &km); /* We do have a shortcut, but only keyboard ones are editable that way... */ if (kmi) { @@ -971,7 +1043,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) } } /* only show 'assign' if there's a suitable key map for it to go in */ - else if (WM_keymap_guess_opname(C, but->optype->idname)) { + else if (WM_keymap_guess_opname(C, idname)) { but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, @@ -990,6 +1062,8 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) UI_but_func_set(but2, popup_add_shortcut_func, but, NULL); } + shortcut_free_operator_property(prop); + /* Set the operator pointer for python access */ uiLayoutSetContextFromBut(layout, but); @@ -1108,6 +1182,9 @@ void ui_popup_context_menu_for_panel(bContext *C, ARegion *ar, Panel *pa) if (!any_item_visible) { return; } + if (pa->type->parent != NULL) { + return; + } RNA_pointer_create(&sc->id, &RNA_Panel, pa, &ptr); diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c index 1d90139eade..658aa4f67f9 100644 --- a/source/blender/editors/interface/interface_eyedropper_datablock.c +++ b/source/blender/editors/interface/interface_eyedropper_datablock.c @@ -207,7 +207,7 @@ static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id) RNA_id_pointer_create(id, &ptr_value); - RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value); + RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value, NULL); RNA_property_update(C, &ddr->ptr, ddr->prop); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 8f19f40d1c0..b9c77b13401 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -551,6 +551,23 @@ static bool ui_but_dragedit_update_mval(uiHandleButtonData *data, int mx) return true; } +static void ui_but_update_preferences_dirty(uiBut *but) +{ + /* Not very elegant, but ensures preference changes force re-save. */ + bool tag = false; + if (but->rnaprop) { + StructRNA *base = RNA_struct_base(but->rnapoin.type); + if (ELEM(base, &RNA_AddonPreferences, &RNA_KeyConfigPreferences, &RNA_KeyMapItem)) { + tag = true; + } + } + + if (tag) { + U.runtime.is_dirty = true; + WM_main_add_notifier(NC_WINDOW, NULL); + } +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1334,6 +1351,9 @@ static bool ui_drag_toggle_set_xy_xy( if (do_check) { ui_but_update_edited(but); } + if (U.runtime.is_dirty == false) { + ui_but_update_preferences_dirty(but); + } changed = true; } } @@ -1715,7 +1735,7 @@ static void ui_selectcontext_apply(bContext *C, } else if (rna_type == PROP_POINTER) { const PointerRNA other_value = delta.p; - RNA_property_pointer_set(&lptr, lprop, other_value); + RNA_property_pointer_set(&lptr, lprop, other_value, NULL); } RNA_property_update(C, &lptr, prop); @@ -3769,7 +3789,7 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat } if (func || handlefunc) { - data->menu = ui_popup_block_create(C, data->region, but, func, handlefunc, arg); + data->menu = ui_popup_block_create(C, data->region, but, func, handlefunc, arg, NULL); if (but->block->handle) { data->menu->popup = but->block->handle->popup; } @@ -3949,6 +3969,9 @@ static int ui_do_but_HOTKEYEVT(bContext *C, if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { return WM_UI_HANDLER_CONTINUE; } + else if (event->type == UNKNOWNKEY) { + return WM_UI_HANDLER_CONTINUE; + } if (event->type == LEFTMOUSE && event->val == KM_PRESS) { /* only cancel if click outside the button */ @@ -5619,6 +5642,13 @@ static int ui_do_but_UNITVEC( } } } + else if (event->type == ESCKEY || event->type == RIGHTMOUSE) { + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } + } else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { button_activate_state(C, but, BUTTON_STATE_EXIT); } @@ -6491,7 +6521,7 @@ static int ui_do_but_CURVE( CurveMap *cuma = cumap->cm + cumap->cur; CurveMapPoint *cmp; const float m_xy[2] = {mx, my}; - float dist_min_sq = SQUARE(14.0f); /* 14 pixels radius */ + float dist_min_sq = SQUARE(U.dpi_fac * 14.0f); /* 14 pixels radius */ int sel = -1; if (event->ctrl) { @@ -6526,7 +6556,7 @@ static int ui_do_but_CURVE( BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[0].x); /* with 160px height 8px should translate to the old 0.05 coefficient at no zoom */ - dist_min_sq = SQUARE(8.0f); + dist_min_sq = SQUARE(U.dpi_fac * 8.0f); /* loop through the curve segment table and find what's near the mouse. */ for (i = 1; i <= CM_TABLE; i++) { @@ -7563,6 +7593,10 @@ static void button_activate_exit( if (block->flag & UI_BLOCK_POPUP_MEMORY) { ui_popup_menu_memory_set(block, but); } + + if (U.runtime.is_dirty == false) { + ui_but_update_preferences_dirty(but); + } } /* disable tooltips until mousemove + last active flag */ diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 7e295f83390..fa3605269ff 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -37,6 +37,7 @@ #include "BLI_utildefines.h" #include "BLI_fileops_types.h" #include "BLI_math_vector.h" +#include "BLI_math_color_blend.h" #include "DNA_brush_types.h" #include "DNA_curve_types.h" @@ -83,6 +84,7 @@ # define ICON_GRID_COLS 26 # define ICON_GRID_ROWS 30 +# define ICON_MONO_BORDER_OUTSET 2 # define ICON_GRID_MARGIN 10 # define ICON_GRID_W 32 # define ICON_GRID_H 32 @@ -138,7 +140,8 @@ typedef struct DrawInfo { } DrawInfo; typedef struct IconTexture { - GLuint id; + GLuint id[2]; + int num_textures; int w; int h; float invw; @@ -154,12 +157,13 @@ typedef struct IconType { /* static here to cache results of icon directory scan, so it's not * scanning the filesystem each time the menu is drawn */ static struct ListBase iconfilelist = {NULL, NULL}; -static IconTexture icongltex = {0, 0, 0, 0.0f, 0.0f}; +static IconTexture icongltex = {{0, 0}, 0, 0, 0, 0.0f, 0.0f}; #ifndef WITH_HEADLESS static const IconType icontypes[] = { # define DEF_ICON(name) {ICON_TYPE_MONO_TEXTURE, 0}, +# define DEF_ICON_SCENE(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_SCENE}, # define DEF_ICON_COLLECTION(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_COLLECTION}, # define DEF_ICON_OBJECT(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT}, # define DEF_ICON_OBJECT_DATA(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT_DATA}, @@ -713,38 +717,146 @@ static void icon_verify_datatoc(IconImage *iimg) } } -static void init_internal_icons(void) +static ImBuf *create_mono_icon_with_border(ImBuf *buf, + int resolution_divider, + float border_intensity) { - // bTheme *btheme = UI_GetTheme(); - ImBuf *b16buf = NULL, *b32buf = NULL; - int x, y; + ImBuf *result = IMB_dupImBuf(buf); + const float border_sharpness = 16.0 / (resolution_divider * resolution_divider); -# if 0 // temp disabled - if ((btheme != NULL) && btheme->tui.iconfile[0]) { - char *icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons"); - char iconfilestr[FILE_MAX]; + float blurred_alpha_buffer[(ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) * + (ICON_GRID_H + 2 * ICON_MONO_BORDER_OUTSET)]; + const int icon_width = (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) / resolution_divider; + const int icon_height = (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) / resolution_divider; - if (icondir) { - BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile); + for (int y = 0; y < ICON_GRID_ROWS; y++) { + for (int x = 0; x < ICON_GRID_COLS; x++) { + IconType icontype = icontypes[y * ICON_GRID_COLS + x]; + if (icontype.type != ICON_TYPE_MONO_TEXTURE) { + continue; + } - /* if the image is missing bbuf will just be NULL */ - bbuf = IMB_loadiffname(iconfilestr, IB_rect, NULL); + int sx = x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN - ICON_MONO_BORDER_OUTSET; + int sy = y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN - ICON_MONO_BORDER_OUTSET; + sx = sx / resolution_divider; + sy = sy / resolution_divider; + + /* blur the alpha channel and store it in blurred_alpha_buffer */ + int blur_size = 2 / resolution_divider; + for (int bx = 0; bx < icon_width; bx++) { + const int asx = MAX2(bx - blur_size, 0); + const int aex = MIN2(bx + blur_size + 1, icon_width); + for (int by = 0; by < icon_height; by++) { + const int asy = MAX2(by - blur_size, 0); + const int aey = MIN2(by + blur_size + 1, icon_height); + + // blur alpha channel + const int write_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx; + float alpha_accum = 0.0; + unsigned int alpha_samples = 0; + for (int ax = asx; ax < aex; ax++) { + for (int ay = asy; ay < aey; ay++) { + const int offset_read = (sy + ay) * buf->x + (sx + ax); + unsigned int color_read = buf->rect[offset_read]; + const float alpha_read = ((color_read & 0xff000000) >> 24) / 255.0; + alpha_accum += alpha_read; + alpha_samples += 1; + } + } + blurred_alpha_buffer[write_offset] = alpha_accum / alpha_samples; + } + } - if (bbuf && (bbuf->x < ICON_IMAGE_W || bbuf->y < ICON_IMAGE_H)) { - printf( - "\n***WARNING***\n" - "Icons file '%s' too small.\n" - "Using built-in Icons instead\n", - iconfilestr); - IMB_freeImBuf(bbuf); - bbuf = NULL; + /* apply blurred alpha */ + for (int bx = 0; bx < icon_width; bx++) { + for (int by = 0; by < icon_height; by++) { + const int blurred_alpha_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx; + const int offset_write = (sy + by) * buf->x + (sx + bx); + const float blurred_alpha = blurred_alpha_buffer[blurred_alpha_offset]; + float border_srgb[4] = { + 0, 0, 0, MIN2(1.0, blurred_alpha * border_sharpness) * border_intensity}; + + const unsigned int color_read = buf->rect[offset_write]; + const unsigned char *orig_color = (unsigned char *)&color_read; + + float border_rgba[4]; + float orig_rgba[4]; + float dest_rgba[4]; + float dest_srgb[4]; + + srgb_to_linearrgb_v4(border_rgba, border_srgb); + srgb_to_linearrgb_uchar4(orig_rgba, orig_color); + blend_color_interpolate_float(dest_rgba, orig_rgba, border_rgba, 1.0 - orig_rgba[3]); + linearrgb_to_srgb_v4(dest_srgb, dest_rgba); + + unsigned int alpha_mask = ((unsigned int)(dest_srgb[3] * 255)) << 24; + unsigned int cpack = rgb_to_cpack(dest_srgb[0], dest_srgb[1], dest_srgb[2]) | alpha_mask; + result->rect[offset_write] = cpack; + } } } - else { - printf("%s: 'icons' data path not found, continuing\n", __func__); + } + return result; +} + +/* Generate the mipmap levels for the icon textures + * During creation the source16 ImBuf will be freed to reduce memory overhead + * A new ImBuf will be returned that needs is owned by the caller. + * + * FIXME: Mipmap levels are generated until the width of the image is 1, which + * are too many levels than that are needed.*/ +static ImBuf *create_mono_icon_mipmaps(ImBuf *source32, ImBuf *source16, int level) +{ + if (level == 0) { + glTexImage2D(GL_TEXTURE_2D, + level, + GL_RGBA8, + source32->x, + source32->y, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + source32->rect); + return create_mono_icon_mipmaps(source32, source16, level + 1); + } + else { + glTexImage2D(GL_TEXTURE_2D, + level, + GL_RGBA8, + source16->x, + source16->y, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + source16->rect); + if (source16->x > 1) { + ImBuf *nbuf = IMB_onehalf(source16); + IMB_freeImBuf(source16); + source16 = create_mono_icon_mipmaps(source32, nbuf, level + 1); } + return source16; } -# endif +} + +static void free_icons_textures(void) +{ + if (icongltex.num_textures > 0) { + glDeleteTextures(icongltex.num_textures, icongltex.id); + icongltex.id[0] = 0; + icongltex.id[1] = 0; + icongltex.num_textures = 0; + } +} + +/* Reload the textures for internal icons. + * This function will release the previous textures. */ +void UI_icons_reload_internal_textures(void) +{ + bTheme *btheme = UI_GetTheme(); + ImBuf *b16buf = NULL, *b32buf = NULL, *b16buf_border = NULL, *b32buf_border = NULL; + const float icon_border_intensity = btheme->tui.icon_border_intensity; + bool need_icons_with_border = icon_border_intensity > 0.0f; + if (b16buf == NULL) { b16buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons16_png, datatoc_blender_icons16_png_size, @@ -753,6 +865,10 @@ static void init_internal_icons(void) "<blender icons>"); } if (b16buf) { + if (need_icons_with_border) { + b16buf_border = create_mono_icon_with_border(b16buf, 2, icon_border_intensity); + IMB_premultiply_alpha(b16buf_border); + } IMB_premultiply_alpha(b16buf); } @@ -764,88 +880,97 @@ static void init_internal_icons(void) "<blender icons>"); } if (b32buf) { + if (need_icons_with_border) { + b32buf_border = create_mono_icon_with_border(b32buf, 1, icon_border_intensity); + IMB_premultiply_alpha(b32buf_border); + } IMB_premultiply_alpha(b32buf); } if (b16buf && b32buf) { /* Free existing texture if any. */ - if (icongltex.id) { - glDeleteTextures(1, &icongltex.id); - icongltex.id = 0; - } + free_icons_textures(); /* Allocate OpenGL texture. */ - glGenTextures(1, &icongltex.id); - - if (icongltex.id) { - int level = 2; + icongltex.num_textures = need_icons_with_border ? 2 : 1; + glGenTextures(icongltex.num_textures, icongltex.id); + if (icongltex.id[0]) { icongltex.w = b32buf->x; icongltex.h = b32buf->y; icongltex.invw = 1.0f / b32buf->x; icongltex.invh = 1.0f / b32buf->y; - glBindTexture(GL_TEXTURE_2D, icongltex.id); - - glTexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA8, - b32buf->x, - b32buf->y, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - b32buf->rect); - glTexImage2D(GL_TEXTURE_2D, - 1, - GL_RGBA8, - b16buf->x, - b16buf->y, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - b16buf->rect); - - while (b16buf->x > 1) { - ImBuf *nbuf = IMB_onehalf(b16buf); - glTexImage2D(GL_TEXTURE_2D, - level, - GL_RGBA8, - nbuf->x, - nbuf->y, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - nbuf->rect); - level++; - IMB_freeImBuf(b16buf); - b16buf = nbuf; - } - + glBindTexture(GL_TEXTURE_2D, icongltex.id[0]); + b16buf = create_mono_icon_mipmaps(b32buf, b16buf, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + } + if (need_icons_with_border && icongltex.id[1]) { + glBindTexture(GL_TEXTURE_2D, icongltex.id[1]); + b16buf_border = create_mono_icon_mipmaps(b32buf_border, b16buf_border, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); } + } - /* Define icons. */ - for (y = 0; y < ICON_GRID_ROWS; y++) { - /* Row W has monochrome icons. */ - for (x = 0; x < ICON_GRID_COLS; x++) { - IconType icontype = icontypes[y * ICON_GRID_COLS + x]; - if (!ELEM(icontype.type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) { - continue; - } + IMB_freeImBuf(b16buf); + IMB_freeImBuf(b32buf); + IMB_freeImBuf(b16buf_border); + IMB_freeImBuf(b32buf_border); +} - def_internal_icon(b32buf, - BIFICONID_FIRST + y * ICON_GRID_COLS + x, - x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, - y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, - ICON_GRID_W, - icontype.type, - icontype.theme_color); +static void init_internal_icons(void) +{ + int x, y; + +# if 0 // temp disabled + if ((btheme != NULL) && btheme->tui.iconfile[0]) { + char *icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons"); + char iconfilestr[FILE_MAX]; + + if (icondir) { + BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile); + + /* if the image is missing bbuf will just be NULL */ + bbuf = IMB_loadiffname(iconfilestr, IB_rect, NULL); + + if (bbuf && (bbuf->x < ICON_IMAGE_W || bbuf->y < ICON_IMAGE_H)) { + printf( + "\n***WARNING***\n" + "Icons file '%s' too small.\n" + "Using built-in Icons instead\n", + iconfilestr); + IMB_freeImBuf(bbuf); + bbuf = NULL; } } + else { + printf("%s: 'icons' data path not found, continuing\n", __func__); + } + } +# endif + + /* Define icons. */ + for (y = 0; y < ICON_GRID_ROWS; y++) { + /* Row W has monochrome icons. */ + for (x = 0; x < ICON_GRID_COLS; x++) { + IconType icontype = icontypes[y * ICON_GRID_COLS + x]; + if (!ELEM(icontype.type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) { + continue; + } + + def_internal_icon(NULL, + BIFICONID_FIRST + y * ICON_GRID_COLS + x, + x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, + y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, + ICON_GRID_W, + icontype.type, + icontype.theme_color); + } } def_internal_vicon(ICON_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw); @@ -882,9 +1007,6 @@ static void init_internal_icons(void) def_internal_vicon(ICON_COLORSET_18_VEC, vicon_colorset_draw_18); def_internal_vicon(ICON_COLORSET_19_VEC, vicon_colorset_draw_19); def_internal_vicon(ICON_COLORSET_20_VEC, vicon_colorset_draw_20); - - IMB_freeImBuf(b16buf); - IMB_freeImBuf(b32buf); } # endif /* WITH_HEADLESS */ @@ -964,6 +1086,12 @@ static void free_iconfile_list(struct ListBase *list) } } +#else + +void UI_icons_reload_internal_textures(void) +{ +} + #endif /* WITH_HEADLESS */ int UI_iconfile_get_index(const char *filename) @@ -990,11 +1118,7 @@ ListBase *UI_iconfile_list(void) void UI_icons_free(void) { #ifndef WITH_HEADLESS - if (icongltex.id) { - glDeleteTextures(1, &icongltex.id); - icongltex.id = 0; - } - + free_icons_textures(); free_iconfile_list(&iconfilelist); BKE_icons_free(); #endif @@ -1104,10 +1228,22 @@ int UI_icon_get_height(int icon_id) return 0; } +bool UI_icon_get_theme_color(int icon_id, uchar color[4]) +{ + Icon *icon = BKE_icon_get(icon_id); + if (icon == NULL) { + return false; + } + + DrawInfo *di = icon_ensure_drawinfo(icon); + return UI_GetIconThemeColor4ubv(di->data.texture.theme_color, color); +} + void UI_icons_init() { #ifndef WITH_HEADLESS init_iconfile_list(&iconfilelist); + UI_icons_reload_internal_textures(); init_internal_icons(); init_brush_icons(); init_event_icons(); @@ -1348,7 +1484,6 @@ static void icon_draw_rect(float x, int rh, uint *rect, float alpha, - const float rgb[3], const float desaturate) { ImBuf *ima = NULL; @@ -1366,12 +1501,6 @@ static void icon_draw_rect(float x, /* modulate color */ float col[4] = {1.0f, 1.0f, 1.0f, alpha}; - if (rgb) { - col[0] = rgb[0]; - col[1] = rgb[1]; - col[2] = rgb[2]; - } - /* rect contains image in 'rendersize', we only scale if needed */ if (rw != w || rh != h) { /* preserve aspect ratio and center */ @@ -1439,12 +1568,17 @@ typedef struct IconDrawCall { float color[4]; } IconDrawCall; -static struct { +typedef struct IconTextureDrawCall { IconDrawCall drawcall_cache[ICON_DRAW_CACHE_SIZE]; int calls; /* Number of calls batched together */ +} IconTextureDrawCall; + +static struct { + IconTextureDrawCall normal; + IconTextureDrawCall border; bool enabled; float mat[4][4]; -} g_icon_draw_cache = {{{{0}}}}; +} g_icon_draw_cache = {{{{{0}}}}}; void UI_icon_draw_cache_begin(void) { @@ -1452,19 +1586,15 @@ void UI_icon_draw_cache_begin(void) g_icon_draw_cache.enabled = true; } -static void icon_draw_cache_flush_ex(void) +static void icon_draw_cache_texture_flush_ex(GLuint texture, + IconTextureDrawCall *texture_draw_calls) { - if (g_icon_draw_cache.calls == 0) { + if (texture_draw_calls->calls == 0) { return; } - /* We need to flush widget base first to ensure correct ordering. */ - UI_widgetbase_draw_cache_flush(); - - GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, icongltex.id); + glBindTexture(GL_TEXTURE_2D, texture); GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR); GPU_shader_bind(shader); @@ -1473,16 +1603,43 @@ static void icon_draw_cache_flush_ex(void) int data_loc = GPU_shader_get_uniform_ensure(shader, "calls_data[0]"); glUniform1i(img_loc, 0); - glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)g_icon_draw_cache.drawcall_cache); + glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache); - GPU_draw_primitive(GPU_PRIM_TRIS, 6 * g_icon_draw_cache.calls); + GPU_draw_primitive(GPU_PRIM_TRIS, 6 * texture_draw_calls->calls); glBindTexture(GL_TEXTURE_2D, 0); - g_icon_draw_cache.calls = 0; + texture_draw_calls->calls = 0; +} + +static void icon_draw_cache_flush_ex(bool only_full_caches) +{ + bool should_draw = false; + if (only_full_caches) { + should_draw = g_icon_draw_cache.normal.calls == ICON_DRAW_CACHE_SIZE || + g_icon_draw_cache.border.calls == ICON_DRAW_CACHE_SIZE; + } + else { + should_draw = g_icon_draw_cache.normal.calls || g_icon_draw_cache.border.calls; + } - GPU_blend_set_func_separate( - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + if (should_draw) { + /* We need to flush widget base first to ensure correct ordering. */ + UI_widgetbase_draw_cache_flush(); + + GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + if (!only_full_caches || g_icon_draw_cache.normal.calls == ICON_DRAW_CACHE_SIZE) { + icon_draw_cache_texture_flush_ex(icongltex.id[0], &g_icon_draw_cache.normal); + } + + if (!only_full_caches || g_icon_draw_cache.border.calls == ICON_DRAW_CACHE_SIZE) { + icon_draw_cache_texture_flush_ex(icongltex.id[1], &g_icon_draw_cache.border); + } + + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + } } void UI_icon_draw_cache_end(void) @@ -1491,12 +1648,12 @@ void UI_icon_draw_cache_end(void) g_icon_draw_cache.enabled = false; /* Don't change blend state if it's not needed. */ - if (g_icon_draw_cache.calls == 0) { + if (g_icon_draw_cache.border.calls == 0 && g_icon_draw_cache.normal.calls == 0) { return; } GPU_blend(true); - icon_draw_cache_flush_ex(); + icon_draw_cache_flush_ex(false); GPU_blend(false); } @@ -1509,14 +1666,18 @@ static void icon_draw_texture_cached(float x, int UNUSED(iw), int ih, float alpha, - const float rgb[3]) + const float rgb[3], + bool with_border) { float mvp[4][4]; GPU_matrix_model_view_projection_get(mvp); - IconDrawCall *call = &g_icon_draw_cache.drawcall_cache[g_icon_draw_cache.calls]; - g_icon_draw_cache.calls++; + IconTextureDrawCall *texture_call = with_border ? &g_icon_draw_cache.border : + &g_icon_draw_cache.normal; + + IconDrawCall *call = &texture_call->drawcall_cache[texture_call->calls]; + texture_call->calls++; /* Manual mat4*vec2 */ call->pos.xmin = x * mvp[0][0] + y * mvp[1][0] + mvp[3][0]; @@ -1536,8 +1697,8 @@ static void icon_draw_texture_cached(float x, copy_v4_fl(call->color, alpha); } - if (g_icon_draw_cache.calls == ICON_DRAW_CACHE_SIZE) { - icon_draw_cache_flush_ex(); + if (texture_call->calls == ICON_DRAW_CACHE_SIZE) { + icon_draw_cache_flush_ex(true); } } @@ -1550,10 +1711,11 @@ static void icon_draw_texture(float x, int iw, int ih, float alpha, - const float rgb[3]) + const float rgb[3], + bool with_border) { if (g_icon_draw_cache.enabled) { - icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb); + icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb, with_border); return; } @@ -1570,7 +1732,7 @@ static void icon_draw_texture(float x, y2 = (iy + ih) * icongltex.invh; glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, icongltex.id); + glBindTexture(GL_TEXTURE_2D, with_border ? icongltex.id[1] : icongltex.id[0]); GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR); GPU_shader_bind(shader); @@ -1614,11 +1776,11 @@ static void icon_draw_size(float x, int icon_id, float aspect, float alpha, - const float rgb[3], enum eIconSizes size, int draw_size, const float desaturate, - const char mono_rgba[4]) + const char mono_rgba[4], + const bool mono_border) { bTheme *btheme = UI_GetTheme(); Icon *icon = NULL; @@ -1675,7 +1837,7 @@ static void icon_draw_size(float x, GPU_blend_set_func_separate( GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->rect, alpha, rgb, desaturate); + icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->rect, alpha, desaturate); GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); } @@ -1695,36 +1857,42 @@ static void icon_draw_size(float x, di->data.texture.w, di->data.texture.h, alpha, - rgb); + NULL, + false); } else if (di->type == ICON_TYPE_MONO_TEXTURE) { - /* icon that matches text color, assumed to be white */ + /* Monochrome icon that uses text or theme color. */ + bool with_border = mono_border && (btheme->tui.icon_border_intensity > 0.0f); float color[4]; - if (!UI_GetIconThemeColor4fv(di->data.texture.theme_color, color)) { - if (mono_rgba) { - rgba_uchar_to_float(color, (const uchar *)mono_rgba); - } - else { - UI_GetThemeColor4fv(TH_TEXT, color); - } + if (mono_rgba) { + rgba_uchar_to_float(color, (const uchar *)mono_rgba); } - - if (rgb) { - mul_v3_v3(color, rgb); + else { + UI_GetThemeColor4fv(TH_TEXT, color); } mul_v4_fl(color, alpha); - icon_draw_texture(x, - y, - (float)w, - (float)h, - di->data.texture.x, - di->data.texture.y, - di->data.texture.w, - di->data.texture.h, + float border_outset = 0.0; + unsigned int border_texel = 0; +#ifndef WITH_HEADLESS + if (with_border) { + const float scale = (float)ICON_GRID_W / (float)ICON_DEFAULT_WIDTH; + border_texel = ICON_MONO_BORDER_OUTSET; + border_outset = ICON_MONO_BORDER_OUTSET / (scale * aspect); + } +#endif + icon_draw_texture(x - border_outset, + y - border_outset, + (float)w + 2 * border_outset, + (float)h + 2 * border_outset, + di->data.texture.x - border_texel, + di->data.texture.y - border_texel, + di->data.texture.w + 2 * border_texel, + di->data.texture.h + 2 * border_texel, color[3], - color); + color, + with_border); } else if (di->type == ICON_TYPE_BUFFER) { @@ -1738,7 +1906,7 @@ static void icon_draw_size(float x, return; } - icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, rgb, desaturate); + icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, desaturate); } else if (di->type == ICON_TYPE_PREVIEW) { PreviewImage *pi = (icon->id_type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : @@ -1755,7 +1923,7 @@ static void icon_draw_size(float x, GPU_blend_set_func_separate( GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); icon_draw_rect( - x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, rgb, desaturate); + x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, desaturate); GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); } @@ -2057,7 +2225,7 @@ int UI_idcode_icon_get(const int idcode) case ID_PC: return ICON_CURVE_BEZCURVE; /* TODO! this would need its own icon! */ case ID_LP: - return ICON_LIGHTPROBE_CUBEMAP; + return ICON_OUTLINER_DATA_LIGHTPROBE; case ID_SCE: return ICON_SCENE_DATA; case ID_SPK: @@ -2077,71 +2245,40 @@ int UI_idcode_icon_get(const int idcode) } } -static void icon_draw_at_size(float x, - float y, - int icon_id, - float aspect, - float alpha, - enum eIconSizes size, - const float desaturate, - const char mono_color[4]) -{ - int draw_size = get_draw_size(size); - icon_draw_size(x, y, icon_id, aspect, alpha, NULL, size, draw_size, desaturate, mono_color); -} - -void UI_icon_draw_aspect( - float x, float y, int icon_id, float aspect, float alpha, const char mono_color[4]) -{ - icon_draw_at_size(x, y, icon_id, aspect, alpha, ICON_SIZE_ICON, 0.0f, mono_color); -} - -void UI_icon_draw_aspect_color( - float x, float y, int icon_id, float aspect, const float rgb[3], const char mono_color[4]) -{ - int draw_size = get_draw_size(ICON_SIZE_ICON); - icon_draw_size(x, y, icon_id, aspect, 1.0f, rgb, ICON_SIZE_ICON, draw_size, false, mono_color); -} - -void UI_icon_draw_desaturate(float x, - float y, - int icon_id, - float aspect, - float alpha, - float desaturate, - const char mono_color[4]) -{ - icon_draw_at_size(x, y, icon_id, aspect, alpha, ICON_SIZE_ICON, desaturate, mono_color); -} - /* draws icon with dpi scale factor */ void UI_icon_draw(float x, float y, int icon_id) { - UI_icon_draw_aspect(x, y, icon_id, 1.0f / UI_DPI_FAC, 1.0f, NULL); + UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false); } void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha) { - UI_icon_draw_aspect(x, y, icon_id, 1.0f / UI_DPI_FAC, alpha, NULL); + UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false); } -void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha) +void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size) { - icon_draw_size(x, y, icon_id, 1.0f, alpha, NULL, ICON_SIZE_ICON, size, false, NULL); + icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, false, NULL, false); } -void UI_icon_draw_preview(float x, float y, int icon_id) +void UI_icon_draw_ex(float x, + float y, + int icon_id, + float aspect, + float alpha, + float desaturate, + const char mono_color[4], + const bool mono_border) { - icon_draw_at_size(x, y, icon_id, 1.0f, 1.0f, ICON_SIZE_PREVIEW, false, NULL); -} - -void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect) -{ - icon_draw_at_size(x, y, icon_id, aspect, 1.0f, ICON_SIZE_PREVIEW, false, NULL); -} - -void UI_icon_draw_preview_aspect_size( - float x, float y, int icon_id, float aspect, float alpha, int size) -{ - icon_draw_size(x, y, icon_id, aspect, alpha, NULL, ICON_SIZE_PREVIEW, size, false, NULL); + int draw_size = get_draw_size(ICON_SIZE_ICON); + icon_draw_size(x, + y, + icon_id, + aspect, + alpha, + ICON_SIZE_ICON, + draw_size, + desaturate, + mono_color, + mono_border); } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 4af7fdd779f..8a2b28ee2d4 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -500,6 +500,7 @@ extern int ui_but_string_get_max_length(uiBut *but); extern uiBut *ui_but_drag_multi_edit_get(uiBut *but); void ui_def_but_icon(uiBut *but, const int icon, const int flag); +void ui_def_but_icon_clear(uiBut *but); extern uiButExtraIconType ui_but_icon_extra_get(uiBut *but); extern void ui_but_default_set(struct bContext *C, const bool all, const bool use_afterfunc); @@ -539,13 +540,12 @@ struct uiKeyNavLock { typedef uiBlock *(*uiBlockHandleCreateFunc)(struct bContext *C, struct uiPopupBlockHandle *handle, void *arg1); -typedef void (*uiBlockHandleFreeFunc)(struct uiPopupBlockHandle *handle, void *arg1); struct uiPopupBlockCreate { uiBlockCreateFunc create_func; uiBlockHandleCreateFunc handle_create_func; - uiBlockHandleFreeFunc free_func; void *arg; + void (*arg_free)(void *arg); int event_xy[2]; @@ -662,7 +662,8 @@ uiPopupBlockHandle *ui_popup_block_create(struct bContext *C, uiBut *but, uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func, - void *arg); + void *arg, + void (*arg_free)(void *arg)); uiPopupBlockHandle *ui_popup_menu_create(struct bContext *C, struct ARegion *butregion, uiBut *but, diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 41001ff6d14..a3906879fd7 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -304,10 +304,14 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool layout->item.flag |= UI_ITEM_MIN; } const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - /* it may seem odd that the icon only adds (unit_x / 4) - * but taking margins into account its fine */ - return (UI_fontstyle_string_width(fstyle, name) + - (unit_x * ((compact ? 1.25f : 1.50f) + (icon ? 0.25f : 0.0f)))); + float margin = compact ? 1.25 : 1.50; + if (icon) { + /* It may seem odd that the icon only adds (unit_x / 4) + * but taking margins into account its fine, except + * in compact mode a bit more margin is required. */ + margin += compact ? 0.35 : 0.25; + } + return UI_fontstyle_string_width(fstyle, name) + (unit_x * margin); } else { return unit_x * 10; @@ -480,7 +484,7 @@ static void ui_item_array(uiLayout *layout, int UNUSED(h), bool expand, bool slider, - bool toggle, + int toggle, bool icon_only, bool compact, bool show_text) @@ -687,7 +691,7 @@ static void ui_item_array(uiLayout *layout, if (slider && but->type == UI_BTYPE_NUM) { but->type = UI_BTYPE_NUM_SLIDER; } - if (toggle && but->type == UI_BTYPE_CHECKBOX) { + if ((toggle == 1) && but->type == UI_BTYPE_CHECKBOX) { but->type = UI_BTYPE_TOGGLE; } if ((a == 0) && (subtype == PROP_AXISANGLE)) { @@ -760,7 +764,8 @@ static void ui_item_enum_expand_elem_exec(uiLayout *layout, if (RNA_property_flag(prop) & PROP_ENUM_FLAG) { /* If this is set, assert since we're clobbering someone elses callback. */ - BLI_assert(but->func == NULL); + /* Buttons get their block's func by default, so we cannot assert in that case either. */ + BLI_assert(ELEM(but->func, NULL, block->func)); UI_but_func_set(but, ui_item_enum_expand_handle, but, POINTER_FROM_INT(value)); } @@ -1450,7 +1455,6 @@ void uiItemsFullEnumO_items(uiLayout *layout, if (properties) { if (tptr.data) { IDP_FreeProperty(tptr.data); - MEM_freeN(tptr.data); } tptr.data = IDP_CopyProperty(properties); } @@ -1854,12 +1858,7 @@ void uiItemFullR(uiLayout *layout, int icon) { uiBlock *block = layout->root->block; - uiBut *but = NULL; - PropertyType type; char namestr[UI_MAX_NAME_STR]; - int len, w, h; - bool slider, toggle, expand, icon_only, no_bg, compact; - bool is_array; const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0); /* By default 'use_prop_sep' uses a separate column for labels. @@ -1884,11 +1883,15 @@ void uiItemFullR(uiLayout *layout, UI_block_layout_set_current(block, layout); /* retrieve info */ - type = RNA_property_type(prop); - is_array = RNA_property_array_check(prop); - len = (is_array) ? RNA_property_array_length(ptr, prop) : 0; + const PropertyType type = RNA_property_type(prop); + const bool is_array = RNA_property_array_check(prop); + const int len = (is_array) ? RNA_property_array_length(ptr, prop) : 0; + + const bool icon_only = (flag & UI_ITEM_R_ICON_ONLY) != 0; - icon_only = (flag & UI_ITEM_R_ICON_ONLY) != 0; + /* Boolean with -1 to signify that the value depends on the presence of an icon. */ + const int toggle = ((flag & UI_ITEM_R_TOGGLE) ? 1 : ((flag & UI_ITEM_R_ICON_NEVER) ? 0 : -1)); + const bool no_icon = (toggle == 0); /* set name and icon */ if (!name) { @@ -1900,8 +1903,8 @@ void uiItemFullR(uiLayout *layout, } } - if (icon == ICON_NONE) { - icon = RNA_property_ui_icon(prop); + if (type != PROP_BOOLEAN) { + flag &= ~UI_ITEM_R_CHECKBOX_INVERT; } if (flag & UI_ITEM_R_ICON_ONLY) { @@ -1928,56 +1931,66 @@ void uiItemFullR(uiLayout *layout, } } -#ifdef UI_PROP_SEP_ICON_WIDTH_EXCEPTION - if (use_prop_sep) { - if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) { - use_prop_sep_split_label = false; + if (no_icon == false) { + if (icon == ICON_NONE) { + icon = RNA_property_ui_icon(prop); } - } -#endif - /* menus and pie-menus don't show checkbox without this */ - if ((layout->root->type == UI_LAYOUT_MENU) || - /* use checkboxes only as a fallback in pie-menu's, when no icon is defined */ - ((layout->root->type == UI_LAYOUT_PIEMENU) && (icon == ICON_NONE))) { - int prop_flag = RNA_property_flag(prop); - if (type == PROP_BOOLEAN && ((is_array == false) || (index != RNA_NO_INDEX))) { - if (prop_flag & PROP_ICONS_CONSECUTIVE) { - icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */ - } - else if (is_array) { - icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT : - ICON_CHECKBOX_DEHLT; + /* Menus and pie-menus don't show checkbox without this. */ + if ((layout->root->type == UI_LAYOUT_MENU) || + /* Use checkboxes only as a fallback in pie-menu's, when no icon is defined. */ + ((layout->root->type == UI_LAYOUT_PIEMENU) && (icon == ICON_NONE))) { + int prop_flag = RNA_property_flag(prop); + if (type == PROP_BOOLEAN) { + if ((is_array == false) || (index != RNA_NO_INDEX)) { + if (prop_flag & PROP_ICONS_CONSECUTIVE) { + icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */ + } + else if (is_array) { + icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT : + ICON_CHECKBOX_DEHLT; + } + else { + icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; + } + } } - else { - icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; + else if (type == PROP_ENUM) { + if (index == RNA_ENUM_VALUE) { + int enum_value = RNA_property_enum_get(ptr, prop); + if (prop_flag & PROP_ICONS_CONSECUTIVE) { + icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */ + } + else if (prop_flag & PROP_ENUM_FLAG) { + icon = (enum_value & value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; + } + else { + icon = (enum_value == value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; + } + } } } - else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) { - int enum_value = RNA_property_enum_get(ptr, prop); - if (prop_flag & PROP_ICONS_CONSECUTIVE) { - icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */ - } - else if (prop_flag & PROP_ENUM_FLAG) { - icon = (enum_value & value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; - } - else { - icon = (enum_value == value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; - } + } + +#ifdef UI_PROP_SEP_ICON_WIDTH_EXCEPTION + if (use_prop_sep) { + if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) { + use_prop_sep_split_label = false; } } +#endif if ((type == PROP_ENUM) && (RNA_property_flag(prop) & PROP_ENUM_FLAG)) { flag |= UI_ITEM_R_EXPAND; } - slider = (flag & UI_ITEM_R_SLIDER) != 0; - toggle = (flag & UI_ITEM_R_TOGGLE) != 0; - expand = (flag & UI_ITEM_R_EXPAND) != 0; - no_bg = (flag & UI_ITEM_R_NO_BG) != 0; - compact = (flag & UI_ITEM_R_COMPACT) != 0; + const bool slider = (flag & UI_ITEM_R_SLIDER) != 0; + const bool expand = (flag & UI_ITEM_R_EXPAND) != 0; + const bool no_bg = (flag & UI_ITEM_R_NO_BG) != 0; + const bool compact = (flag & UI_ITEM_R_COMPACT) != 0; /* get size */ + int w, h; ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, compact, &w, &h); int prev_emboss = layout->emboss; @@ -1985,6 +1998,8 @@ void uiItemFullR(uiLayout *layout, layout->emboss = UI_EMBOSS_NONE; } + uiBut *but = NULL; + /* Split the label / property. */ uiLayout *layout_parent = layout; if (use_prop_sep) { @@ -2152,7 +2167,13 @@ void uiItemFullR(uiLayout *layout, but->type = UI_BTYPE_NUM_SLIDER; } - if (toggle && but->type == UI_BTYPE_CHECKBOX) { + if (flag & UI_ITEM_R_CHECKBOX_INVERT) { + if (ELEM(but->type, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N)) { + but->drawflag |= UI_BUT_CHECKBOX_INVERT; + } + } + + if ((toggle == 1) && but->type == UI_BTYPE_CHECKBOX) { but->type = UI_BTYPE_TOGGLE; } @@ -2171,6 +2192,18 @@ void uiItemFullR(uiLayout *layout, } } + /* The resulting button may have the icon set since boolean button drawing + * is being 'helpful' and adding an icon for us. + * In this case we want the ability not to have an icon. + * + * We could pass an argument not to set the icon to begin with however this is the one case + * the functionality is needed. */ + if (but && no_icon) { + if ((icon == ICON_NONE) && (but->icon != ICON_NONE)) { + ui_def_but_icon_clear(but); + } + } + /* Mark non-embossed textfields inside a listbox. */ if (but && (block->flag & UI_BLOCK_LIST_ITEM) && (but->type == UI_BTYPE_TEXT) && (but->dt & UI_EMBOSS_NONE)) { diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 87e58a4b3b5..9c5ce0c9d2c 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -258,43 +258,16 @@ static void panels_collapse_all(ScrArea *sa, ARegion *ar, const Panel *from_pa) } } -static void ui_panel_copy_offset(Panel *pa, Panel *papar) -{ - /* with respect to sizes... papar is parent */ - - pa->ofsx = papar->ofsx; - pa->ofsy = papar->ofsy + papar->sizey - pa->sizey; -} - -/** - * XXX Disabled paneltab handling for now. Old 2.4x feature, - * *DO NOT* confuse it with new tool tabs in 2.70. ;) - * See also T41704. - */ -/* #define UI_USE_PANELTAB */ - Panel *UI_panel_find_by_type(ListBase *lb, PanelType *pt) { Panel *pa; const char *idname = pt->idname; -#ifdef UI_USE_PANELTAB - const char *tabname = pt->idname; - for (pa = lb->first; pa; pa = pa->next) { - if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) { - if (STREQLEN(pa->tabname, tabname, sizeof(pa->tabname))) { - return pa; - } - } - } -#else for (pa = lb->first; pa; pa = pa->next) { if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) { return pa; } } -#endif - return NULL; } @@ -307,10 +280,6 @@ Panel *UI_panel_begin( Panel *palast, *panext; const char *drawname = CTX_IFACE_(pt->translation_context, pt->label); const char *idname = pt->idname; -#ifdef UI_USE_PANELTAB - const char *tabname = pt->idname; - const char *hookname = NULL; -#endif const bool newpanel = (pa == NULL); int align = panel_aligned(sa, ar); @@ -341,28 +310,6 @@ Panel *UI_panel_begin( pa->runtime_flag |= PNL_NEW_ADDED; BLI_addtail(lb, pa); - -#ifdef UI_USE_PANELTAB - BLI_strncpy(pa->tabname, tabname, sizeof(pa->tabname)); - - /* make new Panel tabbed? */ - if (hookname) { - Panel *patab; - for (patab = lb->first; patab; patab = patab->next) { - if ((patab->runtime_flag & PNL_ACTIVE) && patab->paneltab == NULL) { - if (STREQLEN(hookname, patab->panelname, sizeof(patab->panelname))) { - if (STREQLEN(tabname, patab->tabname, sizeof(patab->tabname))) { - pa->paneltab = patab; - ui_panel_copy_offset(pa, patab); - break; - } - } - } - } - } -#else - BLI_strncpy(pa->tabname, idname, sizeof(pa->tabname)); -#endif } /* Do not allow closed panels without headers! Else user could get "disappeared" UI! */ @@ -411,9 +358,6 @@ Panel *UI_panel_begin( *r_open = false; - if (pa->paneltab) { - return pa; - } if (pa->flag & PNL_CLOSED) { return pa; } @@ -423,7 +367,7 @@ Panel *UI_panel_begin( return pa; } -void UI_panel_end(uiBlock *block, int width, int height) +void UI_panel_end(uiBlock *block, int width, int height, bool open) { Panel *pa = block->panel; @@ -446,21 +390,21 @@ void UI_panel_end(uiBlock *block, int width, int height) pa->sizey = height; } else { - /* check if we need to do an animation */ - if (!ELEM(width, 0, pa->sizex) || !ELEM(height, 0, pa->sizey)) { - pa->runtime_flag |= PNL_ANIM_ALIGN; - if (height != 0) { - pa->ofsy += pa->sizey - height; - } - } + int old_sizex = pa->sizex, old_sizey = pa->sizey; /* update width/height if non-zero */ if (width != 0) { pa->sizex = width; } - if (height != 0) { + if (height != 0 || open) { pa->sizey = height; } + + /* check if we need to do an animation */ + if (pa->sizex != old_sizex || pa->sizey != old_sizey) { + pa->runtime_flag |= PNL_ANIM_ALIGN; + pa->ofsy += old_sizey - pa->sizey; + } } } @@ -705,11 +649,17 @@ void ui_draw_aligned_panel(uiStyle *style, /* FIXME(campbell): currently no background means floating panel which * can't be dragged. This may be changed in future. */ show_background); + const int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK; - if (panel->paneltab) { - return; - } if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { + if (show_background) { + uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(panel_col); + immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + immUnbindProgram(); + } return; } @@ -765,12 +715,14 @@ void ui_draw_aligned_panel(uiStyle *style, panel_title_color_get(show_background, col_title); GPU_blend(true); - UI_icon_draw_aspect(headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect), - headrect.ymin + (5.0f / block->aspect), - (panel->flag & PNL_PIN) ? ICON_PINNED : ICON_UNPINNED, - (block->aspect / UI_DPI_FAC), - 1.0f, - (const char *)col_title); + UI_icon_draw_ex(headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect), + headrect.ymin + (5.0f / block->aspect), + (panel->flag & PNL_PIN) ? ICON_PINNED : ICON_UNPINNED, + (block->aspect * U.inv_dpi_fac), + 1.0f, + 0.0f, + (const char *)col_title, + false); GPU_blend(false); } @@ -838,8 +790,6 @@ void ui_draw_aligned_panel(uiStyle *style, if (show_background) { /* panel backdrop */ - int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK; - immUniformThemeColor(panel_col); immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); } @@ -934,12 +884,6 @@ static int get_panel_real_ofsy(Panel *pa) if (pa->flag & PNL_CLOSEDY) { return pa->ofsy + pa->sizey; } - else if (pa->paneltab && (pa->paneltab->flag & PNL_CLOSEDY)) { - return pa->ofsy + pa->sizey; - } - else if (pa->paneltab) { - return pa->paneltab->ofsy; - } else { return pa->ofsy; } @@ -950,9 +894,6 @@ static int get_panel_real_ofsx(Panel *pa) if (pa->flag & PNL_CLOSEDX) { return pa->ofsx + get_panel_header(pa); } - else if (pa->paneltab && (pa->paneltab->flag & PNL_CLOSEDX)) { - return pa->ofsx + get_panel_header(pa); - } else { return pa->ofsx + pa->sizex; } @@ -1067,7 +1008,7 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo /* count active, not tabbed panels */ for (pa = ar->panels.first; pa; pa = pa->next) { - if ((pa->runtime_flag & PNL_ACTIVE) && pa->paneltab == NULL) { + if (pa->runtime_flag & PNL_ACTIVE) { tot++; } } @@ -1078,7 +1019,7 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo /* extra; change close direction? */ for (pa = ar->panels.first; pa; pa = pa->next) { - if ((pa->runtime_flag & PNL_ACTIVE) && pa->paneltab == NULL) { + if (pa->runtime_flag & PNL_ACTIVE) { if ((pa->flag & PNL_CLOSEDX) && (align == BUT_VERTICAL)) { pa->flag ^= PNL_CLOSED; } @@ -1093,7 +1034,7 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo ps = panelsort; for (pa = ar->panels.first; pa; pa = pa->next) { - if ((pa->runtime_flag & PNL_ACTIVE) && pa->paneltab == NULL) { + if (pa->runtime_flag & PNL_ACTIVE) { ps->pa = MEM_dupallocN(pa); ps->orig = pa; ps++; @@ -1160,9 +1101,6 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo /* set locations for tabbed and sub panels */ for (pa = ar->panels.first; pa; pa = pa->next) { if (pa->runtime_flag & PNL_ACTIVE) { - if (pa->paneltab) { - ui_panel_copy_offset(pa, pa->paneltab); - } if (pa->children.first) { align_sub_panels(pa); } @@ -1265,7 +1203,7 @@ void UI_panels_end(const bContext *C, ARegion *ar, int *r_x, int *r_y) { ScrArea *sa = CTX_wm_area(C); uiBlock *block; - Panel *panot, *panew, *patest, *pa, *firstpa; + Panel *pa, *firstpa; /* offset contents */ for (block = ar->uiblocks.first; block; block = block->next) { @@ -1274,31 +1212,6 @@ void UI_panels_end(const bContext *C, ARegion *ar, int *r_x, int *r_y) } } - /* consistency; are panels not made, whilst they have tabs */ - for (panot = ar->panels.first; panot; panot = panot->next) { - if ((panot->runtime_flag & PNL_ACTIVE) == 0) { /* not made */ - - for (panew = ar->panels.first; panew; panew = panew->next) { - if ((panew->runtime_flag & PNL_ACTIVE)) { - if (panew->paneltab == panot) { /* panew is tab in notmade pa */ - break; - } - } - } - /* now panew can become the new parent, check all other tabs */ - if (panew) { - for (patest = ar->panels.first; patest; patest = patest->next) { - if (patest->paneltab == panot) { - patest->paneltab = panew; - } - } - panot->paneltab = panew; - panew->paneltab = NULL; - ED_region_tag_redraw(ar); /* the buttons panew were not made */ - } - } - } - /* re-align, possibly with animation */ if (panels_need_realign(sa, ar, &pa)) { if (pa) { @@ -1380,7 +1293,7 @@ static void check_panel_overlap(ARegion *ar, Panel *panel) for (pa = ar->panels.first; pa; pa = pa->next) { pa->flag &= ~PNL_OVERLAP; if (panel && (pa != panel)) { - if (pa->paneltab == NULL && (pa->runtime_flag & PNL_ACTIVE)) { + if (pa->runtime_flag & PNL_ACTIVE) { float safex = 0.2, safey = 0.2; if (pa->flag & PNL_CLOSEDX) { @@ -1623,11 +1536,11 @@ static void ui_handle_panel_header( { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); - Panel *pa; #ifdef USE_PIN_HIDDEN - const bool show_pin = UI_panel_category_is_visible(ar) && (block->panel->flag & PNL_PIN); + const bool show_pin = UI_panel_category_is_visible(ar) && (block->panel->type->parent == NULL) && + (block->panel->flag & PNL_PIN); #else - const bool show_pin = UI_panel_category_is_visible(ar); + const bool show_pin = UI_panel_category_is_visible(ar) && (block->panel->type->parent == NULL); #endif const bool is_subpanel = (block->panel->type && block->panel->type->parent); const bool show_drag = !is_subpanel; @@ -1658,8 +1571,10 @@ static void ui_handle_panel_header( button = 1; } else if (ELEM(event, 0, RETKEY, LEFTMOUSE) && shift) { - block->panel->flag ^= PNL_PIN; - button = 2; + if (block->panel->type->parent == NULL) { + block->panel->flag ^= PNL_PIN; + button = 2; + } } else if (block->panel->flag & PNL_CLOSEDX) { if (my >= block->rect.ymax) { @@ -1720,17 +1635,6 @@ static void ui_handle_panel_header( ui_panel_drag_collapse_handler_add(C, true); } } - - for (pa = ar->panels.first; pa; pa = pa->next) { - if (pa->paneltab == block->panel) { - if (block->panel->flag & PNL_CLOSED) { - pa->flag |= PNL_CLOSED; - } - else { - pa->flag &= ~PNL_CLOSED; - } - } - } } if (align) { @@ -1772,28 +1676,7 @@ PanelCategoryStack *UI_panel_category_active_find(ARegion *ar, const char *idnam return BLI_findstring(&ar->panels_category_active, idname, offsetof(PanelCategoryStack, idname)); } -const char *UI_panel_category_active_get(ARegion *ar, bool set_fallback) -{ - PanelCategoryStack *pc_act; - - for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) { - if (UI_panel_category_find(ar, pc_act->idname)) { - return pc_act->idname; - } - } - - if (set_fallback) { - PanelCategoryDyn *pc_dyn = ar->panels_category.first; - if (pc_dyn) { - UI_panel_category_active_set(ar, pc_dyn->idname); - return pc_dyn->idname; - } - } - - return NULL; -} - -void UI_panel_category_active_set(ARegion *ar, const char *idname) +static void ui_panel_category_active_set(ARegion *ar, const char *idname, bool fallback) { ListBase *lb = &ar->panels_category_active; PanelCategoryStack *pc_act = UI_panel_category_active_find(ar, idname); @@ -1806,7 +1689,13 @@ void UI_panel_category_active_set(ARegion *ar, const char *idname) BLI_strncpy(pc_act->idname, idname, sizeof(pc_act->idname)); } - BLI_addhead(lb, pc_act); + if (fallback) { + /* For fallbacks, add at the end so explicitly chosen categories have priority. */ + BLI_addtail(lb, pc_act); + } + else { + BLI_addhead(lb, pc_act); + } /* validate all active panels, we could do this on load, * they are harmless - but we should remove somewhere. @@ -1825,6 +1714,39 @@ void UI_panel_category_active_set(ARegion *ar, const char *idname) } } +void UI_panel_category_active_set(ARegion *ar, const char *idname) +{ + ui_panel_category_active_set(ar, idname, false); +} + +void UI_panel_category_active_set_default(ARegion *ar, const char *idname) +{ + if (!UI_panel_category_active_find(ar, idname)) { + ui_panel_category_active_set(ar, idname, true); + } +} + +const char *UI_panel_category_active_get(ARegion *ar, bool set_fallback) +{ + PanelCategoryStack *pc_act; + + for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) { + if (UI_panel_category_find(ar, pc_act->idname)) { + return pc_act->idname; + } + } + + if (set_fallback) { + PanelCategoryDyn *pc_dyn = ar->panels_category.first; + if (pc_dyn) { + ui_panel_category_active_set(ar, pc_dyn->idname, true); + return pc_dyn->idname; + } + } + + return NULL; +} + PanelCategoryDyn *UI_panel_category_find_mouse_over_ex(ARegion *ar, const int x, const int y) { PanelCategoryDyn *ptd; @@ -2067,7 +1989,11 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) ui_fontscale(&fstyle_points, aspect / (U.pixelsize * 1.1f)); BLF_size(fontid, fstyle_points, U.dpi); - BLI_assert(UI_panel_category_is_visible(ar)); + /* Check the region type supports categories to avoid an assert + * for showing 3D view panels in the properties space. */ + if ((1 << ar->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) { + BLI_assert(UI_panel_category_is_visible(ar)); + } /* calculate tab rect's and check if we need to scale down */ for (pc_dyn = ar->panels_category.first; pc_dyn; pc_dyn = pc_dyn->next) { @@ -2378,7 +2304,7 @@ int ui_handler_panel_region(bContext *C, /* checks for mouse position inside */ pa = block->panel; - if (!pa || pa->paneltab != NULL) { + if (!pa) { continue; } /* XXX - accessed freed panels when scripts reload, need to fix. */ diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c index dcbbde259f2..330a9d48ff4 100644 --- a/source/blender/editors/interface/interface_region_menu_pie.c +++ b/source/blender/editors/interface/interface_region_menu_pie.c @@ -208,7 +208,7 @@ void UI_pie_menu_end(bContext *C, uiPieMenu *pie) wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *menu; - menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_PIE, pie); + menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_PIE, pie, NULL); menu->popup = true; menu->towardstime = PIL_check_seconds_timer(); diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c index b97cbcdfef5..ab3a86ec9e1 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.c +++ b/source/blender/editors/interface/interface_region_menu_popup.c @@ -351,7 +351,7 @@ uiPopupBlockHandle *ui_popup_menu_create( pup->menu_func = menu_func; pup->menu_arg = arg; - handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPUP, pup); + handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPUP, pup, NULL); if (!but) { handle->popup = true; @@ -463,7 +463,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup) butregion = pup->butregion; } - menu = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPUP, pup); + menu = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPUP, pup, NULL); menu->popup = true; UI_popup_handlers_add(C, &window->modalhandlers, menu, 0); @@ -581,13 +581,17 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) /** \name Popup Block API * \{ */ -void UI_popup_block_invoke_ex( - bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext) +void UI_popup_block_invoke_ex(bContext *C, + uiBlockCreateFunc func, + void *arg, + void (*arg_free)(void *arg), + const char *opname, + int opcontext) { wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *handle; - handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg); + handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg, arg_free); handle->popup = true; handle->can_refresh = true; handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL; @@ -598,9 +602,12 @@ void UI_popup_block_invoke_ex( WM_event_add_mousemove(C); } -void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg) +void UI_popup_block_invoke(bContext *C, + uiBlockCreateFunc func, + void *arg, + void (*arg_free)(void *arg)) { - UI_popup_block_invoke_ex(C, func, arg, NULL, WM_OP_INVOKE_DEFAULT); + UI_popup_block_invoke_ex(C, func, arg, arg_free, NULL, WM_OP_INVOKE_DEFAULT); } void UI_popup_block_ex(bContext *C, @@ -613,7 +620,7 @@ void UI_popup_block_ex(bContext *C, wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *handle; - handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg); + handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg, NULL); handle->popup = true; handle->retvalue = 1; handle->can_refresh = true; @@ -635,7 +642,7 @@ void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *handle; - handle = ui_popup_block_create(C, NULL, NULL, func, NULL, op); + handle = ui_popup_block_create(C, NULL, NULL, func, NULL, op, NULL); handle->popup = 1; handle->retvalue = 1; handle->can_refresh = true; diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index f149ccd626c..22c62ecd6f7 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -244,7 +244,7 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v return block; } -static void ui_block_free_func_POPOVER(uiPopupBlockHandle *UNUSED(handle), void *arg_pup) +static void ui_block_free_func_POPOVER(void *arg_pup) { uiPopover *pup = arg_pup; if (pup->keymap != NULL) { @@ -282,8 +282,8 @@ uiPopupBlockHandle *ui_popover_panel_create( /* Create popup block. */ uiPopupBlockHandle *handle; - handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPOVER, pup); - handle->popup_create_vars.free_func = ui_block_free_func_POPOVER; + handle = ui_popup_block_create( + C, butregion, but, NULL, ui_block_func_POPOVER, pup, ui_block_free_func_POPOVER); handle->can_refresh = true; /* Add handlers. If attached to a button, the button will already @@ -386,8 +386,8 @@ void UI_popover_end(bContext *C, uiPopover *pup, wmKeyMap *keymap) WM_event_set_keymap_handler_post_callback(pup->keymap_handler, popover_keymap_fn, pup); } - handle = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPOVER, pup); - handle->popup_create_vars.free_func = ui_block_free_func_POPOVER; + handle = ui_popup_block_create( + C, NULL, NULL, NULL, ui_block_func_POPOVER, pup, ui_block_free_func_POPOVER); /* Add handlers. */ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0); diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c index c4bcd7074d8..bd87439ca9e 100644 --- a/source/blender/editors/interface/interface_region_popup.c +++ b/source/blender/editors/interface/interface_region_popup.c @@ -748,7 +748,8 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, uiBut *but, uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func, - void *arg) + void *arg, + void (*arg_free)(void *arg)) { wmWindow *window = CTX_wm_window(C); uiBut *activebut = UI_context_active_but_get(C); @@ -775,6 +776,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, handle->popup_create_vars.create_func = create_func; handle->popup_create_vars.handle_create_func = handle_create_func; handle->popup_create_vars.arg = arg; + handle->popup_create_vars.arg_free = arg_free; handle->popup_create_vars.but = but; handle->popup_create_vars.butregion = but ? butregion : NULL; copy_v2_v2_int(handle->popup_create_vars.event_xy, &window->eventstate->x); @@ -820,8 +822,8 @@ void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle) } } - if (handle->popup_create_vars.free_func) { - handle->popup_create_vars.free_func(handle, handle->popup_create_vars.arg); + if (handle->popup_create_vars.arg_free) { + handle->popup_create_vars.arg_free(handle->popup_create_vars.arg); } ui_popup_block_remove(C, handle); diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 4a9c7b689c1..5b205de21b8 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -891,11 +891,11 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz) } gzop_actions[] = { { .part = gz->highlight_part, - .prefix = use_drag ? TIP_("Click") : NULL, + .prefix = use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Click") : NULL, }, { .part = use_drag ? gz->drag_part : -1, - .prefix = use_drag ? TIP_("Drag") : NULL, + .prefix = use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Drag") : NULL, }, }; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index e96141eaa05..33602818fd4 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -298,7 +298,7 @@ static void template_ID_set_property_cb(bContext *C, void *arg_template, void *i PointerRNA idptr; RNA_id_pointer_create(item, &idptr); - RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); } } @@ -489,7 +489,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_DELETE: memset(&idptr, 0, sizeof(idptr)); - RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, 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) { @@ -532,7 +532,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); } } - RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); } break; @@ -541,7 +541,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) BKE_override_static_free(&id->override_static); /* 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); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); } break; @@ -1455,7 +1455,7 @@ static void template_search_handle_cb(bContext *C, void *arg_template, void *ite PointerRNA item_ptr; RNA_pointer_create(NULL, type, item, &item_ptr); - RNA_property_pointer_set(&coll_search->target_ptr, coll_search->target_prop, item_ptr); + RNA_property_pointer_set(&coll_search->target_ptr, coll_search->target_prop, item_ptr, NULL); RNA_property_update(C, &coll_search->target_ptr, coll_search->target_prop); } @@ -4042,6 +4042,11 @@ static uiBlock *curvemap_brush_tools_func(bContext *C, ARegion *ar, void *cumap_ return curvemap_tools_func(C, ar, cumap_v, false, UICURVE_FUNC_RESET_NEG); } +static uiBlock *curvemap_brush_tools_negslope_func(bContext *C, ARegion *ar, void *cumap_v) +{ + return curvemap_tools_func(C, ar, cumap_v, false, UICURVE_FUNC_RESET_POS); +} + static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2)) { ED_region_tag_redraw(CTX_wm_region(C)); @@ -4217,7 +4222,19 @@ static void curvemap_buttons_layout(uiLayout *layout, TIP_("Zoom out")); UI_but_func_set(bt, curvemap_buttons_zoom_out, cumap, NULL); - if (brush) { + if (brush && neg_slope) { + bt = uiDefIconBlockBut(block, + curvemap_brush_tools_negslope_func, + cumap, + 0, + ICON_DOWNARROW_HLT, + 0, + 0, + dx, + dx, + TIP_("Tools")); + } + else if (brush) { bt = uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, @@ -6744,12 +6761,17 @@ int uiTemplateRecentFiles(uiLayout *layout, int rows) for (recent = G.recent_files.first, i = 0; (i < rows) && (recent); recent = recent->next, i++) { const char *filename = BLI_path_basename(recent->filepath); - uiItemStringO(layout, - filename, - BLO_has_bfile_extension(filename) ? ICON_FILE_BLEND : ICON_FILE_BACKUP, - "WM_OT_open_mainfile", - "filepath", - recent->filepath); + PointerRNA ptr; + uiItemFullO(layout, + "WM_OT_open_mainfile", + filename, + BLO_has_bfile_extension(filename) ? ICON_FILE_BLEND : ICON_FILE_BACKUP, + NULL, + WM_OP_INVOKE_DEFAULT, + 0, + &ptr); + RNA_string_set(&ptr, "filepath", recent->filepath); + RNA_boolean_set(&ptr, "display_file_selector", false); } return i; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index a9cd2f9cee1..e31646f9fdb 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1261,7 +1261,9 @@ void UI_widgetbase_draw_cache_flush(void) (float *)g_widget_base_batch.params); GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params); GPU_matrix_bind(batch->interface); - GPU_batch_draw_range_ex(batch, 0, g_widget_base_batch.count, true); + GPU_batch_bind(batch); + GPU_batch_draw_advanced(batch, 0, 0, 0, g_widget_base_batch.count); + GPU_batch_program_use_end(batch); } g_widget_base_batch.count = 0; @@ -1421,7 +1423,7 @@ static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect) int x = rect->xmin + w / 2 - size / 2; int y = rect->ymin + h / 2 - size / 2; - UI_icon_draw_preview_aspect_size(x, y, icon, 1.0f, alpha, size); + UI_icon_draw_preview(x, y, icon, 1.0f, alpha, size); } } @@ -1450,7 +1452,7 @@ static void widget_draw_icon( return; } - aspect = but->block->aspect / UI_DPI_FAC; + aspect = but->block->aspect * U.inv_dpi_fac; height = ICON_DEFAULT_HEIGHT / aspect; /* calculate blend color */ @@ -1506,18 +1508,27 @@ static void widget_draw_icon( ys = (int)(ys + 0.1f); } + /* Get theme color. */ + char color[4] = {mono_color[0], mono_color[1], mono_color[2], mono_color[3]}; + bool has_theme = UI_icon_get_theme_color(icon, (uchar *)color); + /* to indicate draggable */ if (but->dragpoin && (but->flag & UI_ACTIVE)) { - float rgb[3] = {1.25f, 1.25f, 1.25f}; - UI_icon_draw_aspect_color(xs, ys, icon, aspect, rgb, mono_color); + UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme); } - else if ((but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW)) || !UI_but_is_tool(but)) { - UI_icon_draw_aspect(xs, ys, icon, aspect, alpha, mono_color); + else if ((but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW))) { + UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme); + } + else if (!UI_but_is_tool(but)) { + if (has_theme) { + alpha *= 0.8f; + } + UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme); } else { const bTheme *btheme = UI_GetTheme(); - UI_icon_draw_desaturate( - xs, ys, icon, aspect, alpha, 1.0 - btheme->tui.icon_saturation, mono_color); + const float desaturate = 1.0 - btheme->tui.icon_saturation; + UI_icon_draw_ex(xs, ys, icon, aspect, alpha, desaturate, color, has_theme); } } @@ -1528,7 +1539,7 @@ static void widget_draw_submenu_tria(const uiBut *but, const rcti *rect, const uiWidgetColors *wcol) { - const float aspect = but->block->aspect / UI_DPI_FAC; + const float aspect = but->block->aspect * U.inv_dpi_fac; const int tria_height = (int)(ICON_DEFAULT_HEIGHT / aspect); const int tria_width = (int)(ICON_DEFAULT_WIDTH / aspect) - 2 * U.pixelsize; const int xs = rect->xmax - tria_width; @@ -1584,7 +1595,8 @@ static void ui_text_clip_right_ex(const uiFontStyle *fstyle, BLI_assert(str[0]); /* If the trailing ellipsis takes more than 20% of all available width, just cut the string - * (as using the ellipsis would remove even more useful chars, and we cannot show much already!). + * (as using the ellipsis would remove even more useful chars, and we cannot show much + * already!). */ if (sep_strwidth / okwidth > 0.2f) { l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, &tmp); @@ -1699,7 +1711,8 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle, /* Corner case, the str already takes all available mem, * and the ellipsis chars would actually add more chars. * Better to just trim one or two letters to the right in this case... - * Note: with a single-char ellipsis, this should never happen! But better be safe here... + * Note: with a single-char ellipsis, this should never happen! But better be safe + * here... */ ui_text_clip_right_ex( fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len); @@ -2346,7 +2359,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle, const BIFIconID icon = widget_icon_id(but); int icon_size_init = is_tool ? ICON_DEFAULT_HEIGHT_TOOLBAR : ICON_DEFAULT_HEIGHT; - const float icon_size = icon_size_init / (but->block->aspect / UI_DPI_FAC); + const float icon_size = icon_size_init / (but->block->aspect * U.inv_dpi_fac); const float icon_padding = 2 * UI_DPI_FAC; #ifdef USE_UI_TOOLBAR_HACK @@ -3494,8 +3507,11 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s wcol->item[3] = 255; if (horizontal) { - shape_preset_init_scroll_circle(&wtb.tria1, slider, 0.6f, 'l'); - shape_preset_init_scroll_circle(&wtb.tria2, slider, 0.6f, 'r'); + rcti slider_inset = *slider; + slider_inset.xmin += 0.05 * U.widget_unit; + slider_inset.xmax -= 0.05 * U.widget_unit; + shape_preset_init_scroll_circle(&wtb.tria1, &slider_inset, 0.6f, 'l'); + shape_preset_init_scroll_circle(&wtb.tria2, &slider_inset, 0.6f, 'r'); } else { shape_preset_init_scroll_circle(&wtb.tria1, slider, 0.6f, 'b'); @@ -4631,6 +4647,9 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct break; case UI_BTYPE_COLORBAND: + /* do not draw right to edge of rect */ + rect->xmin += (0.25f * UI_UNIT_X); + rect->xmax -= (0.3f * UI_UNIT_X); ui_draw_but_COLORBAND(but, &tui->wcol_regular, rect); break; @@ -4655,6 +4674,9 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct break; case UI_BTYPE_CURVE: + /* do not draw right to edge of rect */ + rect->xmin += (0.2f * UI_UNIT_X); + rect->xmax -= (0.2f * UI_UNIT_X); ui_draw_but_CURVE(ar, but, &tui->wcol_regular, rect); break; @@ -5198,7 +5220,7 @@ void ui_draw_menu_item( GPU_blend(true); /* XXX scale weak get from fstyle? */ - UI_icon_draw_aspect(xs, ys, iconid, aspect, 1.0f, wt->wcol.text); + UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false); GPU_blend(false); } } diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 587cccf516c..06acf59e07c 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -309,6 +309,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case TH_GRID: cp = ts->grid; break; + case TH_SCRUBBING_BACKGROUND: + cp = ts->scrubbing_background; + break; case TH_VIEW_OVERLAY: cp = ts->view_overlay; break; @@ -792,6 +795,22 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) cp = ts->selected_highlight; break; + case TH_SELECTED_OBJECT: + cp = ts->selected_object; + break; + + case TH_ACTIVE_OBJECT: + cp = ts->active_object; + break; + + case TH_EDITED_OBJECT: + cp = ts->edited_object; + break; + + case TH_ROW_ALTERNATE: + cp = ts->row_alternate; + break; + case TH_SKIN_ROOT: cp = ts->skin_root; break; @@ -865,6 +884,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) cp = btheme->tui.gizmo_b; break; + case TH_ICON_SCENE: + cp = btheme->tui.icon_scene; + break; case TH_ICON_COLLECTION: cp = btheme->tui.icon_collection; break; @@ -881,6 +903,10 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) cp = btheme->tui.icon_shading; break; + case TH_SCROLL_TEXT: + cp = btheme->tui.wcol_scroll.text; + break; + case TH_INFO_SELECTED: cp = ts->info_selected; break; @@ -1347,7 +1373,7 @@ void UI_GetThemeColorType4ubv(int colorid, int spacetype, uchar col[4]) col[3] = cp[3]; } -bool UI_GetIconThemeColor4fv(int colorid, float col[4]) +bool UI_GetIconThemeColor4ubv(int colorid, uchar col[4]) { if (colorid == 0) { return false; @@ -1356,16 +1382,16 @@ bool UI_GetIconThemeColor4fv(int colorid, float col[4]) /* Only colored icons in outliner and popups, overall UI is intended * to stay monochrome and out of the way except a few places where it * is important to communicate different data types. */ - if (!((theme_spacetype == SPACE_OUTLINER) || (theme_regionid == RGN_TYPE_TEMPORARY))) { + if (!((theme_spacetype == SPACE_OUTLINER && theme_regionid == RGN_TYPE_WINDOW) || + (theme_spacetype == SPACE_PROPERTIES && theme_regionid == RGN_TYPE_NAV_BAR))) { return false; } - const uchar *cp; - cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); - col[0] = ((float)cp[0]) / 255.0f; - col[1] = ((float)cp[1]) / 255.0f; - col[2] = ((float)cp[2]) / 255.0f; - col[3] = ((float)cp[3]) / 255.0f; + const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); + col[0] = cp[0]; + col[1] = cp[1]; + col[2] = cp[2]; + col[3] = cp[3]; return true; } diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 58d26c4a840..f2d4faff479 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -138,7 +138,7 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr if (check_scrollers) { /* check size if hiding flag is set: */ if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) { - if (!(v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL)) { + if (!(v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES)) { if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) { v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR; } @@ -148,7 +148,7 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr } } if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) { - if (!(v2d->scroll & V2D_SCROLL_SCALE_VERTICAL)) { + if (!(v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES)) { if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) { v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR; } @@ -166,10 +166,11 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr * - if they overlap, they must not occupy the corners (which are reserved for other widgets) */ if (scroll) { - const int scroll_width = (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) ? V2D_SCROLL_WIDTH_TEXT : - V2D_SCROLL_WIDTH; - const int scroll_height = (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) ? - V2D_SCROLL_HEIGHT_TEXT : + const int scroll_width = (v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) ? + V2D_SCROLL_WIDTH_HANDLES : + V2D_SCROLL_WIDTH; + const int scroll_height = (v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) ? + V2D_SCROLL_HEIGHT_HANDLES : V2D_SCROLL_HEIGHT; /* vertical scroller */ @@ -185,6 +186,13 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr v2d->vert.xmin = v2d->vert.xmax - scroll_width; } + /* Currently, all regions that have vertical scale handles, + * also have the scrubbing area at the top. + * So the scrollbar has to move down a bit. */ + if (scroll & V2D_SCROLL_VERTICAL_HANDLES) { + v2d->vert.ymax -= UI_SCRUBBING_MARGIN_Y; + } + /* horizontal scroller */ if (scroll & (V2D_SCROLL_BOTTOM)) { /* on bottom edge of region */ @@ -1589,7 +1597,7 @@ void UI_view2d_scrollers_draw(View2D *v2d, View2DScrollers *vs) * (workaround to make sure that button windows don't show these, * and only the time-grids with their zoomability can do so) */ - if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 && (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) && + if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 && (v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) && (BLI_rcti_size_x(&slider) > V2D_SCROLLER_HANDLE_SIZE)) { state |= UI_SCROLL_ARROWS; } @@ -1623,7 +1631,7 @@ void UI_view2d_scrollers_draw(View2D *v2d, View2DScrollers *vs) * (workaround to make sure that button windows don't show these, * and only the time-grids with their zoomability can do so) */ - if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 && (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) && + if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 && (v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) && (BLI_rcti_size_y(&slider) > V2D_SCROLLER_HANDLE_SIZE)) { state |= UI_SCROLL_ARROWS; } @@ -1644,59 +1652,6 @@ void UI_view2d_scrollers_free(View2DScrollers *scrollers) /* *********************************************************************** */ /* List View Utilities */ -/** Get the view-coordinates of the nominated cell - * - * \param columnwidth, rowheight: size of each 'cell' - * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from. - * This should be (0,0) for most views. However, for those where the starting row was offsetted - * (like for Animation Editor channel lists, to make the first entry more visible), these will be - * the min-coordinates of the first item. - * \param column, row: The 2d-coordinates - * (in 2D-view / 'tot' rect space) the cell exists at - * \param rect: coordinates of the cell - * (passed as single var instead of 4 separate, as it's more useful this way) - */ -void UI_view2d_listview_cell_to_view(View2D *v2d, - float columnwidth, - float rowheight, - float startx, - float starty, - int column, - int row, - rctf *rect) -{ - /* sanity checks */ - if (ELEM(NULL, v2d, rect)) { - return; - } - - if ((columnwidth <= 0) && (rowheight <= 0)) { - rect->xmin = rect->xmax = 0.0f; - rect->ymin = rect->ymax = 0.0f; - return; - } - - /* x-coordinates */ - rect->xmin = startx + (float)(columnwidth * column); - rect->xmax = startx + (float)(columnwidth * (column + 1)); - - if ((v2d->align & V2D_ALIGN_NO_POS_X) && !(v2d->align & V2D_ALIGN_NO_NEG_X)) { - /* simply negate the values for the coordinates if in negative half */ - rect->xmin = -rect->xmin; - rect->xmax = -rect->xmax; - } - - /* y-coordinates */ - rect->ymin = starty + (float)(rowheight * row); - rect->ymax = starty + (float)(rowheight * (row + 1)); - - if ((v2d->align & V2D_ALIGN_NO_POS_Y) && !(v2d->align & V2D_ALIGN_NO_NEG_Y)) { - /* simply negate the values for the coordinates if in negative half */ - rect->ymin = -rect->ymin; - rect->ymax = -rect->ymax; - } -} - /** * Get the 'cell' (row, column) that the given 2D-view coordinates * (i.e. in 'tot' rect space) lie in. @@ -1709,8 +1664,7 @@ void UI_view2d_listview_cell_to_view(View2D *v2d, * \param viewx, viewy: 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for * \param r_column, r_row: the 'coordinates' of the relevant 'cell' */ -void UI_view2d_listview_view_to_cell(View2D *v2d, - float columnwidth, +void UI_view2d_listview_view_to_cell(float columnwidth, float rowheight, float startx, float starty, @@ -1719,80 +1673,24 @@ void UI_view2d_listview_view_to_cell(View2D *v2d, int *r_column, int *r_row) { - /* adjust view coordinates to be all positive ints, corrected for the start offset */ - const int x = (int)(floorf(fabsf(viewx) + 0.5f) - startx); - const int y = (int)(floorf(fabsf(viewy) + 0.5f) - starty); - - /* sizes must not be negative */ - if ((v2d == NULL) || ((columnwidth <= 0) && (rowheight <= 0))) { - if (r_column) { - *r_column = 0; + if (r_column) { + if (columnwidth > 0) { + /* Columns go from left to right (x increases). */ + *r_column = floorf((viewx - startx) / columnwidth); } - if (r_row) { - *r_row = 0; + else { + *r_column = 0; } - - return; - } - - /* get column */ - if ((r_column) && (columnwidth > 0)) { - *r_column = x / columnwidth; - } - else if (r_column) { - *r_column = 0; } - /* get row */ - if ((r_row) && (rowheight > 0)) { - *r_row = y / rowheight; - } - else if (r_row) { - *r_row = 0; - } -} - -/** - * Get the 'extreme' (min/max) column and row indices which are visible within the 'cur' rect - * - * \param columnwidth, rowheight: Size of each 'cell' - * \param startx, starty: Coordinates that the list starts from, - * which should be (0,0) for most views. - * \param column_min, column_max, row_min, row_max: The starting and ending column/row indices - */ -void UI_view2d_listview_visible_cells(View2D *v2d, - float columnwidth, - float rowheight, - float startx, - float starty, - int *column_min, - int *column_max, - int *row_min, - int *row_max) -{ - /* using 'cur' rect coordinates, call the cell-getting function to get the cells for this */ - if (v2d) { - /* min */ - UI_view2d_listview_view_to_cell(v2d, - columnwidth, - rowheight, - startx, - starty, - v2d->cur.xmin, - v2d->cur.ymin, - column_min, - row_min); - - /* max*/ - UI_view2d_listview_view_to_cell(v2d, - columnwidth, - rowheight, - startx, - starty, - v2d->cur.xmax, - v2d->cur.ymax, - column_max, - row_max); + if (r_row) { + if (rowheight > 0) { + /* Rows got from top to bottom (y decreases). */ + *r_row = floorf((starty - viewy) / rowheight); + } + else { + *r_row = 0; + } } } diff --git a/source/blender/editors/interface/view2d_draw.c b/source/blender/editors/interface/view2d_draw.c index 91128e49a60..2009bbecebc 100644 --- a/source/blender/editors/interface/view2d_draw.c +++ b/source/blender/editors/interface/view2d_draw.c @@ -53,7 +53,7 @@ /* Compute display grid resolution ********************************************************/ -#define MIN_MAJOR_LINE_DISTANCE (UI_DPI_FAC * 50) +#define MIN_MAJOR_LINE_DISTANCE (U.v2d_min_gridsize * UI_DPI_FAC) static float select_major_distance(const float *possible_distances, uint amount, @@ -153,6 +153,12 @@ static void get_parallel_lines_draw_steps(const ParallelLinesSet *lines, float *r_first, uint *r_steps) { + if (region_start >= region_end) { + *r_first = 0; + *r_steps = 0; + return; + } + BLI_assert(lines->distance > 0); BLI_assert(region_start <= region_end); @@ -258,7 +264,8 @@ static void draw_horizontal_scale_indicators(const ARegion *ar, float distance, const rcti *rect, PositionToString to_string, - void *to_string_data) + void *to_string_data, + int colorid) { GPU_matrix_push_projection(); wmOrtho2_region_pixelspace(ar); @@ -277,7 +284,7 @@ static void draw_horizontal_scale_indicators(const ARegion *ar, } const int font_id = BLF_default(); - UI_FontThemeColor(font_id, TH_TEXT); + UI_FontThemeColor(font_id, colorid); BLF_batch_draw_begin(); @@ -308,7 +315,8 @@ static void draw_vertical_scale_indicators(const ARegion *ar, float display_offset, const rcti *rect, PositionToString to_string, - void *to_string_data) + void *to_string_data, + int colorid) { GPU_matrix_push_projection(); wmOrtho2_region_pixelspace(ar); @@ -327,7 +335,7 @@ static void draw_vertical_scale_indicators(const ARegion *ar, } const int font_id = BLF_default(); - UI_FontThemeColor(font_id, TH_TEXT); + UI_FontThemeColor(font_id, colorid); BLF_enable(font_id, BLF_ROTATION); BLF_rotation(font_id, M_PI_2); @@ -463,51 +471,62 @@ void UI_view2d_draw_lines_x__frames_or_seconds(const View2D *v2d, /* Scale indicator text drawing API **************************************************/ -void UI_view2d_draw_scale_x__discrete_values(const ARegion *ar, - const View2D *v2d, - const rcti *rect) +static void UI_view2d_draw_scale_x__discrete_values(const ARegion *ar, + const View2D *v2d, + const rcti *rect, + int colorid) { float number_step = view2d_major_step_x__discrete(v2d); - draw_horizontal_scale_indicators(ar, v2d, number_step, rect, view_to_string__frame_number, NULL); + draw_horizontal_scale_indicators( + ar, v2d, number_step, rect, view_to_string__frame_number, NULL, colorid); } -void UI_view2d_draw_scale_x__discrete_time(const ARegion *ar, - const View2D *v2d, - const rcti *rect, - const Scene *scene) +static void UI_view2d_draw_scale_x__discrete_time( + const ARegion *ar, const View2D *v2d, const rcti *rect, const Scene *scene, int colorid) { float step = view2d_major_step_x__time(v2d, scene); - draw_horizontal_scale_indicators(ar, v2d, step, rect, view_to_string__time, (void *)scene); + draw_horizontal_scale_indicators( + ar, v2d, step, rect, view_to_string__time, (void *)scene, colorid); } -void UI_view2d_draw_scale_x__values(const ARegion *ar, const View2D *v2d, const rcti *rect) +static void UI_view2d_draw_scale_x__values(const ARegion *ar, + const View2D *v2d, + const rcti *rect, + int colorid) { float step = view2d_major_step_x__continuous(v2d); - draw_horizontal_scale_indicators(ar, v2d, step, rect, view_to_string__value, NULL); + draw_horizontal_scale_indicators(ar, v2d, step, rect, view_to_string__value, NULL, colorid); } -void UI_view2d_draw_scale_y__values(const ARegion *ar, const View2D *v2d, const rcti *rect) +void UI_view2d_draw_scale_y__values(const ARegion *ar, + const View2D *v2d, + const rcti *rect, + int colorid) { float step = view2d_major_step_y__continuous(v2d); - draw_vertical_scale_indicators(ar, v2d, step, 0.0f, rect, view_to_string__value, NULL); + draw_vertical_scale_indicators(ar, v2d, step, 0.0f, rect, view_to_string__value, NULL, colorid); } -void UI_view2d_draw_scale_y__block(const ARegion *ar, const View2D *v2d, const rcti *rect) +void UI_view2d_draw_scale_y__block(const ARegion *ar, + const View2D *v2d, + const rcti *rect, + int colorid) { - draw_vertical_scale_indicators(ar, v2d, 1.0f, 0.5f, rect, view_to_string__value, NULL); + draw_vertical_scale_indicators(ar, v2d, 1.0f, 0.5f, rect, view_to_string__value, NULL, colorid); } void UI_view2d_draw_scale_x__discrete_frames_or_seconds(const struct ARegion *ar, const struct View2D *v2d, const struct rcti *rect, const struct Scene *scene, - bool display_seconds) + bool display_seconds, + int colorid) { if (display_seconds) { - UI_view2d_draw_scale_x__discrete_time(ar, v2d, rect, scene); + UI_view2d_draw_scale_x__discrete_time(ar, v2d, rect, scene, colorid); } else { - UI_view2d_draw_scale_x__discrete_values(ar, v2d, rect); + UI_view2d_draw_scale_x__discrete_values(ar, v2d, rect, colorid); } } @@ -515,12 +534,13 @@ void UI_view2d_draw_scale_x__frames_or_seconds(const struct ARegion *ar, const struct View2D *v2d, const struct rcti *rect, const struct Scene *scene, - bool display_seconds) + bool display_seconds, + int colorid) { if (display_seconds) { - UI_view2d_draw_scale_x__discrete_time(ar, v2d, rect, scene); + UI_view2d_draw_scale_x__discrete_time(ar, v2d, rect, scene, colorid); } else { - UI_view2d_draw_scale_x__values(ar, v2d, rect); + UI_view2d_draw_scale_x__values(ar, v2d, rect, colorid); } } diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index ab8d1cf9bf6..68ee38bc99f 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -2032,8 +2032,8 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent * * NOTE: see view2d.c for latest conditions, and keep this in sync with that */ if (ELEM(vsm->zone, SCROLLHANDLE_MIN, SCROLLHANDLE_MAX)) { - if (((vsm->scroller == 'h') && (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) == 0) || - ((vsm->scroller == 'v') && (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) == 0)) { + if (((vsm->scroller == 'h') && (v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) == 0) || + ((vsm->scroller == 'v') && (v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) == 0)) { /* switch to bar (i.e. no scaling gets handled) */ vsm->zone = SCROLLHANDLE_BAR; } diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index 3dd3b20bda3..9fdcec71cfd 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -108,7 +108,7 @@ static int cachefile_open_exec(bContext *C, wmOperator *op) PointerRNA idptr; RNA_id_pointer_create(&cache_file->id, &idptr); - RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); + RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); RNA_property_update(C, &pprop->ptr, pprop->prop); } diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index c0f3b1f8338..1f825c0bb31 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -1992,9 +1992,9 @@ static int mask_hide_view_clear_exec(bContext *C, wmOperator *op) for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { - if (masklay->restrictflag & OB_RESTRICT_VIEW) { + if (masklay->restrictflag & OB_RESTRICT_VIEWPORT) { ED_mask_layer_select_set(masklay, select); - masklay->restrictflag &= ~OB_RESTRICT_VIEW; + masklay->restrictflag &= ~OB_RESTRICT_VIEWPORT; changed = true; } } @@ -2045,7 +2045,7 @@ static int mask_hide_view_set_exec(bContext *C, wmOperator *op) if (ED_mask_layer_select_check(masklay)) { ED_mask_layer_select_set(masklay, false); - masklay->restrictflag |= OB_RESTRICT_VIEW; + masklay->restrictflag |= OB_RESTRICT_VIEWPORT; changed = true; if (masklay == BKE_mask_layer_active(mask)) { BKE_mask_layer_active_set(mask, NULL); @@ -2054,7 +2054,7 @@ static int mask_hide_view_set_exec(bContext *C, wmOperator *op) } else { if (!ED_mask_layer_select_check(masklay)) { - masklay->restrictflag |= OB_RESTRICT_VIEW; + masklay->restrictflag |= OB_RESTRICT_VIEWPORT; changed = true; if (masklay == BKE_mask_layer_active(mask)) { BKE_mask_layer_active_set(mask, NULL); diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 57bf67e825e..9a779db4812 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -23,6 +23,7 @@ set(INC ../../blentranslation ../../bmesh ../../depsgraph + ../../draw ../../gpu ../../imbuf ../../makesdna diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 990250792a1..d61c340f7a2 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -441,74 +441,6 @@ bool paintface_mouse_select( return true; } -bool do_paintface_box_select(ViewContext *vc, const rcti *rect, int sel_op) -{ - Object *ob = vc->obact; - Mesh *me; - - me = BKE_mesh_from_object(ob); - if ((me == NULL) || (me->totpoly == 0)) { - return false; - } - - bool changed = false; - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - changed |= paintface_deselect_all_visible(vc->C, vc->obact, SEL_DESELECT, false); - } - - if (BLI_rcti_is_empty(rect)) { - /* pass */ - } - else { - MPoly *mpoly; - uint *rt; - int a, index; - - char *selar = MEM_callocN(me->totpoly + 1, "selar"); - - uint buf_len; - uint *buf = ED_view3d_select_id_read_rect(vc, rect, &buf_len); - - rt = buf; - - a = buf_len; - while (a--) { - if (*rt) { - index = *rt; - if (index <= me->totpoly) { - selar[index] = 1; - } - } - rt++; - } - - mpoly = me->mpoly; - for (a = 1; a <= me->totpoly; a++, mpoly++) { - if ((mpoly->flag & ME_HIDE) == 0) { - const bool is_select = mpoly->flag & ME_FACE_SEL; - const bool is_inside = (selar[a] != 0); - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); - if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL); - changed = true; - } - } - } - - MEM_freeN(buf); - MEM_freeN(selar); - -#ifdef __APPLE__ - glReadBuffer(GL_BACK); -#endif - } - - if (changed) { - paintface_flush_flags(vc->C, vc->obact, SELECT); - } - return changed; -} - /* (similar to void paintface_flush_flags(Object *ob)) * copy the vertex flags, most importantly selection from the mesh to the final derived mesh, * use in object mode when selecting vertices (while painting) */ diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c index 839ee186016..f6729fb56e1 100644 --- a/source/blender/editors/mesh/editmesh_add_gizmo.c +++ b/source/blender/editors/mesh/editmesh_add_gizmo.c @@ -29,6 +29,7 @@ #include "BKE_context.h" #include "BKE_editmesh.h" +#include "BKE_scene.h" #include "ED_gizmo_library.h" #include "ED_gizmo_utils.h" @@ -75,7 +76,7 @@ static void calc_initial_placement_point_from_view(bContext *C, float cursor_matrix[4][4]; float orient_matrix[3][3]; - ED_view3d_cursor3d_calc_mat4(scene, cursor_matrix); + BKE_scene_cursor_to_mat4(&scene->cursor, cursor_matrix); float dots[3] = { dot_v3v3(rv3d->viewinv[2], cursor_matrix[0]), diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index f6940cae953..1cd4e95314b 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -907,7 +907,8 @@ void MESH_OT_bevel(wmOperatorType *ot) /* identifiers */ ot->name = "Bevel"; - ot->description = "Edge Bevel"; + ot->description = + "Cut into selected items at an angle to create flat or rounded bevel or chamfer"; ot->idname = "MESH_OT_bevel"; /* api callbacks */ diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c index bc60ff9274f..1d173d8e396 100644 --- a/source/blender/editors/mesh/editmesh_bisect.c +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -148,7 +148,7 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event) BisectData *opdata; opdata = MEM_mallocN(sizeof(BisectData), "inset_operator_data"); - gesture->userdata = opdata; + gesture->user_data.data = opdata; opdata->backup_len = objects_len; opdata->backup = MEM_callocN(sizeof(*opdata->backup) * objects_len, __func__); @@ -193,7 +193,7 @@ static void edbm_bisect_exit(bContext *C, BisectData *opdata) static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event) { wmGesture *gesture = op->customdata; - BisectData *opdata = gesture->userdata; + BisectData *opdata = gesture->user_data.data; BisectData opdata_back = *opdata; /* annoyance, WM_gesture_straightline_modal, frees */ int ret; @@ -276,7 +276,7 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op) } wmGesture *gesture = op->customdata; - BisectData *opdata = (gesture != NULL) ? gesture->userdata : NULL; + BisectData *opdata = (gesture != NULL) ? gesture->user_data.data : NULL; /* -------------------------------------------------------------------- */ /* Modal support */ diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 82cff8363f8..0da4d20c6b5 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -36,6 +36,7 @@ #include "RNA_access.h" #include "WM_types.h" +#include "WM_api.h" #include "ED_mesh.h" #include "ED_screen.h" @@ -860,6 +861,9 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w EDBM_mesh_normals_update(vc.em); EDBM_update_generic(vc.em, true, true); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } MEM_freeN(objects); diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index cc0c2f5bbe4..976dbe01a22 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1156,19 +1156,20 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO); GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR); + GPU_batch_bind(batch); /* draw any snapped verts first */ rgba_uchar_to_float(fcol, kcd->colors.point_a); GPU_batch_uniform_4fv(batch, "color", fcol); GPU_matrix_bind(batch->interface); GPU_point_size(11); - GPU_batch_draw_range_ex(batch, 0, v - 1, false); + GPU_batch_draw_advanced(batch, 0, v - 1, 0, 0); /* now draw the rest */ rgba_uchar_to_float(fcol, kcd->colors.curpoint_a); GPU_batch_uniform_4fv(batch, "color", fcol); GPU_point_size(7); - GPU_batch_draw_range_ex(batch, vs + 1, kcd->totlinehit - (vs + 1), false); + GPU_batch_draw_advanced(batch, vs + 1, kcd->totlinehit - (vs + 1), 0, 0); GPU_batch_program_use_end(batch); GPU_batch_discard(batch); @@ -2811,6 +2812,7 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) {KNF_MODAL_CUT_THROUGH_TOGGLE, "CUT_THROUGH_TOGGLE", 0, "Toggle Cut Through", ""}, {KNF_MODAL_NEW_CUT, "NEW_CUT", 0, "End Current Cut", ""}, {KNF_MODAL_ADD_CUT, "ADD_CUT", 0, "Add Cut", ""}, + {KNF_MODAL_ADD_CUT_CLOSED, "ADD_CUT_CLOSED", 0, "Add Cut Closed", ""}, {KNF_MODAL_PANNING, "PANNING", 0, "Panning", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 528235e693a..59355890428 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -79,11 +79,11 @@ typedef struct RingSelOpData { Depsgraph *depsgraph; - Object **objects; - uint objects_len; + Base **bases; + uint bases_len; /* These values switch objects based on the object under the cursor. */ - uint ob_index; + uint base_index; Object *ob; BMEditMesh *em; BMEdge *eed; @@ -111,8 +111,8 @@ static void edgering_select(RingSelOpData *lcd) } if (!lcd->extend) { - for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) { - Object *ob_iter = lcd->objects[ob_index]; + for (uint base_index = 0; base_index < lcd->bases_len; base_index++) { + Object *ob_iter = lcd->bases[base_index]->object; BMEditMesh *em = BKE_editmesh_from_object(ob_iter); EDBM_flag_disable_all(em, BM_ELEM_SELECT); DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); @@ -252,7 +252,7 @@ static void ringsel_exit(bContext *UNUSED(C), wmOperator *op) EDBM_preselect_edgering_destroy(lcd->presel_edgering); - MEM_freeN(lcd->objects); + MEM_freeN(lcd->bases); ED_region_tag_redraw(lcd->ar); @@ -307,21 +307,21 @@ static void ringcut_cancel(bContext *C, wmOperator *op) } static void loopcut_update_edge(RingSelOpData *lcd, - uint ob_index, + uint base_index, BMEdge *e, const int previewlines) { if (e != lcd->eed) { lcd->eed = e; lcd->ob = lcd->vc.obedit; - lcd->ob_index = ob_index; + lcd->base_index = base_index; lcd->em = lcd->vc.em; ringsel_find_edge(lcd, previewlines); } else if (e == NULL) { lcd->ob = NULL; lcd->em = NULL; - lcd->ob_index = UINT_MAX; + lcd->base_index = UINT_MAX; } } @@ -331,27 +331,26 @@ static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines) Object *ob; BMEdge *eed; float dist; - int ob_index; + int base_index; } best = { .dist = ED_view3d_select_dist_px(), }; - for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) { - Object *ob_iter = lcd->objects[ob_index]; - ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter); - BMEdge *eed_test = EDBM_edge_find_nearest_ex(&lcd->vc, &best.dist, NULL, false, false, NULL); - if (eed_test) { - best.ob = ob_iter; - best.eed = eed_test; - best.ob_index = ob_index; - } + uint base_index; + BMEdge *eed_test = EDBM_edge_find_nearest_ex( + &lcd->vc, &best.dist, NULL, false, false, NULL, lcd->bases, lcd->bases_len, &base_index); + + if (eed_test) { + best.ob = lcd->bases[base_index]->object; + best.eed = eed_test; + best.base_index = base_index; } if (best.eed) { ED_view3d_viewcontext_init_object(&lcd->vc, best.ob); } - loopcut_update_edge(lcd, best.ob_index, best.eed, previewlines); + loopcut_update_edge(lcd, best.base_index, best.eed, previewlines); } /* called by both init() and exec() */ @@ -361,22 +360,22 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) /* Use for redo - intentionally wrap int to uint. */ const struct { - uint ob_index; + uint base_index; uint e_index; } exec_data = { - .ob_index = (uint)RNA_int_get(op->ptr, "object_index"), + .base_index = (uint)RNA_int_get(op->ptr, "object_index"), .e_index = (uint)RNA_int_get(op->ptr, "edge_index"), }; ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( - view_layer, CTX_wm_view3d(C), &objects_len); + uint bases_len; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode( + view_layer, CTX_wm_view3d(C), &bases_len); if (is_interactive) { - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob_iter = objects[ob_index]; + for (uint base_index = 0; base_index < bases_len; base_index++) { + Object *ob_iter = bases[base_index]->object; if (modifiers_isDeformedByLattice(ob_iter) || modifiers_isDeformedByArmature(ob_iter)) { BKE_report( op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display"); @@ -390,12 +389,12 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) /* for re-execution, check edge index is in range before we setup ringsel */ bool ok = true; if (is_interactive == false) { - if (exec_data.ob_index >= objects_len) { + if (exec_data.base_index >= bases_len) { return OPERATOR_CANCELLED; ok = false; } else { - Object *ob_iter = objects[exec_data.ob_index]; + Object *ob_iter = bases[exec_data.base_index]->object; BMEditMesh *em = BKE_editmesh_from_object(ob_iter); if (exec_data.e_index >= em->bm->totedge) { ok = false; @@ -404,7 +403,7 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) } if (!ok || !ringsel_init(C, op, true)) { - MEM_freeN(objects); + MEM_freeN(bases); return OPERATOR_CANCELLED; } @@ -416,8 +415,8 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) RingSelOpData *lcd = op->customdata; - lcd->objects = objects; - lcd->objects_len = objects_len; + lcd->bases = bases; + lcd->bases_len = bases_len; if (is_interactive) { copy_v2_v2_int(lcd->vc.mval, event->mval); @@ -425,13 +424,13 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) } else { - Object *ob_iter = objects[exec_data.ob_index]; + Object *ob_iter = bases[exec_data.base_index]->object; ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter); BMEdge *e; BM_mesh_elem_table_ensure(lcd->vc.em->bm, BM_EDGE); e = BM_edge_at_index(lcd->vc.em->bm, exec_data.e_index); - loopcut_update_edge(lcd, exec_data.ob_index, e, 0); + loopcut_update_edge(lcd, exec_data.base_index, e, 0); } #ifdef USE_LOOPSLIDE_HACK @@ -503,7 +502,7 @@ static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op) if (lcd->eed) { /* set for redo */ BM_mesh_elem_index_ensure(lcd->em->bm, BM_EDGE); - RNA_int_set(op->ptr, "object_index", lcd->ob_index); + RNA_int_set(op->ptr, "object_index", lcd->base_index); RNA_int_set(op->ptr, "edge_index", BM_elem_index_get(lcd->eed)); /* execute */ diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index f8ec4334427..6fd0ee83b6c 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -63,6 +63,15 @@ /** \name Path Select Struct & Properties * \{ */ +enum { + EDGE_MODE_SELECT = 0, + EDGE_MODE_TAG_SEAM = 1, + EDGE_MODE_TAG_SHARP = 2, + EDGE_MODE_TAG_CREASE = 3, + EDGE_MODE_TAG_BEVEL = 4, + EDGE_MODE_TAG_FREESTYLE = 5, +}; + struct PathSelectParams { /** ensure the active element is the last selected item (handy for picking) */ bool track_active; @@ -75,6 +84,23 @@ struct PathSelectParams { static void path_select_properties(wmOperatorType *ot) { + static const EnumPropertyItem edge_tag_items[] = { + {EDGE_MODE_SELECT, "SELECT", 0, "Select", ""}, + {EDGE_MODE_TAG_SEAM, "SEAM", 0, "Tag Seam", ""}, + {EDGE_MODE_TAG_SHARP, "SHARP", 0, "Tag Sharp", ""}, + {EDGE_MODE_TAG_CREASE, "CREASE", 0, "Tag Crease", ""}, + {EDGE_MODE_TAG_BEVEL, "BEVEL", 0, "Tag Bevel", ""}, + {EDGE_MODE_TAG_FREESTYLE, "FREESTYLE", 0, "Tag Freestyle Edge Mark", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + RNA_def_enum(ot->srna, + "edge_mode", + edge_tag_items, + EDGE_MODE_SELECT, + "Edge Tag", + "The edge flag to tag when selecting the shortest path"); + RNA_def_boolean(ot->srna, "use_face_step", false, @@ -93,9 +119,24 @@ static void path_select_properties(wmOperatorType *ot) WM_operator_properties_checker_interval(ot, true); } -static void path_select_params_from_op(wmOperator *op, struct PathSelectParams *op_params) +static void path_select_params_from_op(wmOperator *op, + ToolSettings *ts, + struct PathSelectParams *op_params) { - op_params->edge_mode = EDGE_MODE_SELECT; + { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "edge_mode"); + if (RNA_property_is_set(op->ptr, prop)) { + op_params->edge_mode = RNA_property_enum_get(op->ptr, prop); + if (op->flag & OP_IS_INVOKE) { + ts->edge_mode = op_params->edge_mode; + } + } + else { + op_params->edge_mode = ts->edge_mode; + RNA_property_enum_set(op->ptr, prop, op_params->edge_mode); + } + } + op_params->track_active = false; op_params->use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); op_params->use_fill = RNA_boolean_get(op->ptr, "use_fill"); @@ -103,6 +144,21 @@ static void path_select_params_from_op(wmOperator *op, struct PathSelectParams * WM_operator_properties_checker_interval_from_op(op, &op_params->interval_params); } +static bool path_select_poll_property(const bContext *C, + wmOperator *UNUSED(op), + const PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + if (STREQ(prop_id, "edge_mode")) { + const Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + if ((ts->selectmode & SCE_SELECT_EDGE) == 0) { + return false; + } + } + return true; +} + struct UserData { BMesh *bm; Mesh *me; @@ -319,7 +375,7 @@ static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode) /* mesh shortest path select, uses prev-selected edge */ /* since you want to create paths with multiple selects, it doesn't have extend option */ -static void mouse_mesh_shortest_path_edge(Scene *UNUSED(scene), +static void mouse_mesh_shortest_path_edge(Scene *scene, Object *obedit, const struct PathSelectParams *op_params, BMEdge *e_act, @@ -421,6 +477,10 @@ static void mouse_mesh_shortest_path_edge(Scene *UNUSED(scene), } EDBM_update_generic(em, false, false); + + if (op_params->edge_mode == EDGE_MODE_TAG_SEAM) { + ED_uvedit_live_unwrap(scene, &obedit, 1); + } } /** \} */ @@ -649,12 +709,14 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE return OPERATOR_FINISHED; } + struct PathSelectParams op_params; + path_select_params_from_op(op, vc.scene->toolsettings, &op_params); + BMElem *ele_src, *ele_dst; if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) || !(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype))) { /* special case, toggle edge tags even when we don't have a path */ - if (((em->selectmode & SCE_SELECT_EDGE) && - (vc.scene->toolsettings->edge_mode != EDGE_MODE_SELECT)) && + if (((em->selectmode & SCE_SELECT_EDGE) && (op_params.edge_mode != EDGE_MODE_SELECT)) && /* check if we only have a destination edge */ ((ele_src == NULL) && (ele_dst = edbm_elem_find_nearest(&vc, BM_EDGE)))) { ele_src = ele_dst; @@ -665,11 +727,7 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE } } - struct PathSelectParams op_params; - - path_select_params_from_op(op, &op_params); op_params.track_active = track_active; - op_params.edge_mode = vc.scene->toolsettings->edge_mode; if (!edbm_shortest_path_pick_ex(vc.scene, vc.obedit, &op_params, ele_src, ele_dst)) { return OPERATOR_PASS_THROUGH; @@ -707,9 +765,8 @@ static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op) } struct PathSelectParams op_params; - path_select_params_from_op(op, &op_params); + path_select_params_from_op(op, scene->toolsettings, &op_params); op_params.track_active = true; - op_params.edge_mode = scene->toolsettings->edge_mode; if (!edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst)) { return OPERATOR_CANCELLED; @@ -731,6 +788,7 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot) ot->invoke = edbm_shortest_path_pick_invoke; ot->exec = edbm_shortest_path_pick_exec; ot->poll = ED_operator_editmesh_region_view3d; + ot->poll_property = path_select_poll_property; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -832,7 +890,7 @@ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op) if (ele_src && ele_dst) { struct PathSelectParams op_params; - path_select_params_from_op(op, &op_params); + path_select_params_from_op(op, scene->toolsettings, &op_params); edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst); @@ -860,6 +918,7 @@ void MESH_OT_shortest_path_select(wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_shortest_path_select_exec; ot->poll = ED_operator_editmesh; + ot->poll_property = path_select_poll_property; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 9df03a81762..dc94219cb9a 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -53,6 +53,7 @@ #include "ED_mesh.h" #include "ED_screen.h" #include "ED_transform.h" +#include "ED_select_buffer_utils.h" #include "ED_select_utils.h" #include "ED_view3d.h" @@ -67,6 +68,8 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "DRW_engine.h" + #include "mesh_intern.h" /* own include */ /* use bmesh operator flags for a few operators */ @@ -196,186 +199,171 @@ void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag) /** \name Back-Buffer OpenGL Selection * \{ */ -/* set in drawobject.c ... for colorindices */ -unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0; - -/* facilities for box select and circle select */ -static BLI_bitmap *selbuf = NULL; +struct EDBMBaseOffset { + /* For convenience only. */ + union { + uint offset; + uint face_start; + }; + union { + uint face; + uint edge_start; + }; + union { + uint edge; + uint vert_start; + }; + uint vert; +}; -static BLI_bitmap *edbm_backbuf_alloc(const int size) -{ - return BLI_BITMAP_NEW(size, "selbuf"); -} +struct EDBMSelectID_Context { + struct EDBMBaseOffset *base_array_index_offsets; + /** Borrow from caller (not freed). */ + struct Base **bases; + uint bases_len; + /** Total number of items `base_array_index_offsets[bases_len - 1].vert`. */ + uint base_array_index_len; +}; -/* reads rect, and builds selection array for quick lookup */ -/* returns if all is OK */ -bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xmax, short ymax) +static bool check_ob_drawface_dot(short select_mode, const View3D *v3d, char dt) { - uint *buf, *dr, buf_len; - - if (vc->obedit == NULL || XRAY_FLAG_ENABLED(vc->v3d)) { - return false; - } - - buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, &buf_len); - if ((buf == NULL) || (bm_vertoffs == 0)) { - return false; - } - - dr = buf; - - /* build selection lookup */ - selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); - - while (buf_len--) { - if (*dr > 0 && *dr <= bm_vertoffs) { - BLI_BITMAP_ENABLE(selbuf, *dr); + if (select_mode & SCE_SELECT_FACE) { + if (dt < OB_SOLID) { + return true; + } + if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) { + return true; + } + if (XRAY_FLAG_ENABLED(v3d)) { + return true; } - dr++; } - MEM_freeN(buf); - return true; + return false; } -bool EDBM_backbuf_check(unsigned int index) +static void edbm_select_pick_draw_bases(struct EDBMSelectID_Context *sel_id_ctx, + ViewContext *vc, + short select_mode) { - /* odd logic, if selbuf is NULL we assume no zbuf-selection is enabled - * and just ignore the depth buffer, this is error prone since its possible - * code doesn't set the depth buffer by accident, but leave for now. - Campbell */ - if (selbuf == NULL) { - return true; - } + Scene *scene_eval = (Scene *)DEG_get_evaluated_id(vc->depsgraph, &vc->scene->id); + DRW_framebuffer_select_id_setup(vc->ar, true); - if (index > 0 && index <= bm_vertoffs) { - return BLI_BITMAP_TEST_BOOL(selbuf, index); - } + uint offset = 1; + for (uint base_index = 0; base_index < sel_id_ctx->bases_len; base_index++) { + Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, + sel_id_ctx->bases[base_index]->object); - return false; -} + struct EDBMBaseOffset *base_ofs = &sel_id_ctx->base_array_index_offsets[base_index]; + bool draw_facedot = check_ob_drawface_dot(select_mode, vc->v3d, ob_eval->dt); -void EDBM_backbuf_free(void) -{ - if (selbuf) { - MEM_freeN(selbuf); + DRW_draw_select_id_object(scene_eval, + vc->rv3d, + ob_eval, + select_mode, + draw_facedot, + offset, + &base_ofs->vert, + &base_ofs->edge, + &base_ofs->face); + + base_ofs->offset = offset; + offset = base_ofs->vert; } - selbuf = NULL; -} -struct LassoMaskData { - unsigned int *px; - int width; -}; + sel_id_ctx->base_array_index_len = offset; -static void edbm_mask_lasso_px_cb(int x, int x_end, int y, void *user_data) -{ - struct LassoMaskData *data = user_data; - unsigned int *px = &data->px[(y * data->width) + x]; - do { - *px = true; - px++; - } while (++x != x_end); + DRW_framebuffer_select_id_release(vc->ar); } -/* mcords is a polygon mask - * - grab backbuffer, - * - draw with black in backbuffer, - * - grab again and compare - * returns 'OK' - */ -bool EDBM_backbuf_border_mask_init(ViewContext *vc, - const int mcords[][2], - short tot, - short xmin, - short ymin, - short xmax, - short ymax) +BMElem *EDBM_select_id_bm_elem_get(struct EDBMSelectID_Context *sel_id_ctx, + const uint sel_id, + uint *r_base_index) { - uint *buf, *dr, *dr_mask, *dr_mask_arr, buf_len; - struct LassoMaskData lasso_mask_data; - - /* method in use for face selecting too */ - if (vc->obedit == NULL) { - if (!BKE_paint_select_elem_test(vc->obact)) { - return false; + char elem_type; + uint elem_id; + uint base_index = 0; + for (; base_index < sel_id_ctx->bases_len; base_index++) { + struct EDBMBaseOffset *base_ofs = &sel_id_ctx->base_array_index_offsets[base_index]; + if (base_ofs->face > sel_id) { + elem_id = sel_id - base_ofs->face_start; + elem_type = BM_FACE; + break; + } + if (base_ofs->edge > sel_id) { + elem_id = sel_id - base_ofs->edge_start; + elem_type = BM_EDGE; + break; + } + if (base_ofs->vert > sel_id) { + elem_id = sel_id - base_ofs->vert_start; + elem_type = BM_VERT; + break; } - } - else if (XRAY_FLAG_ENABLED(vc->v3d)) { - return false; } - buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, &buf_len); - if ((buf == NULL) || (bm_vertoffs == 0)) { - return false; + if (r_base_index) { + *r_base_index = base_index; } - dr = buf; - - dr_mask = dr_mask_arr = MEM_callocN(sizeof(*dr_mask) * buf_len, __func__); - lasso_mask_data.px = dr_mask; - lasso_mask_data.width = (xmax - xmin) + 1; - - BLI_bitmap_draw_2d_poly_v2i_n( - xmin, ymin, xmax + 1, ymax + 1, mcords, tot, edbm_mask_lasso_px_cb, &lasso_mask_data); - - /* build selection lookup */ - selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); + Object *obedit = sel_id_ctx->bases[base_index]->object; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - while (buf_len--) { - if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) { - BLI_BITMAP_ENABLE(selbuf, *dr); - } - dr++; - dr_mask++; + switch (elem_type) { + case BM_FACE: + return (BMElem *)BM_face_at_index_find_or_table(em->bm, elem_id); + case BM_EDGE: + return (BMElem *)BM_edge_at_index_find_or_table(em->bm, elem_id); + case BM_VERT: + return (BMElem *)BM_vert_at_index_find_or_table(em->bm, elem_id); + default: + BLI_assert(0); + return NULL; } - MEM_freeN(buf); - MEM_freeN(dr_mask_arr); - - return true; } -/* circle shaped sample area */ -bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads) +uint EDBM_select_id_context_offset_for_object_elem(const struct EDBMSelectID_Context *sel_id_ctx, + int base_index, + char htype) { - uint *buf, *dr; - short xmin, ymin, xmax, ymax, xc, yc; - int radsq; - - /* method in use for face selecting too */ - if (vc->obedit == NULL) { - if (!BKE_paint_select_elem_test(vc->obact)) { - return false; - } + struct EDBMBaseOffset *base_ofs = &sel_id_ctx->base_array_index_offsets[base_index]; + if (htype == BM_VERT) { + return base_ofs->vert_start - 1; } - else if (XRAY_FLAG_ENABLED(vc->v3d)) { - return false; + if (htype == BM_EDGE) { + return base_ofs->edge_start - 1; } - - xmin = xs - rads; - xmax = xs + rads; - ymin = ys - rads; - ymax = ys + rads; - buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, NULL); - if ((buf == NULL) || (bm_vertoffs == 0)) { - return false; + if (htype == BM_FACE) { + return base_ofs->face_start - 1; } + BLI_assert(0); + return 0; +} - dr = buf; +uint EDBM_select_id_context_elem_len(const struct EDBMSelectID_Context *sel_id_ctx) +{ + return sel_id_ctx->base_array_index_len; +} - /* build selection lookup */ - selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); - radsq = rads * rads; - for (yc = -rads; yc <= rads; yc++) { - for (xc = -rads; xc <= rads; xc++, dr++) { - if (xc * xc + yc * yc < radsq) { - if (*dr > 0 && *dr <= bm_vertoffs) { - BLI_BITMAP_ENABLE(selbuf, *dr); - } - } - } - } +struct EDBMSelectID_Context *EDBM_select_id_context_create(ViewContext *vc, + Base **bases, + uint bases_len, + short select_mode) +{ + struct EDBMSelectID_Context *sel_id_ctx = MEM_mallocN(sizeof(*sel_id_ctx), __func__); + sel_id_ctx->base_array_index_offsets = MEM_mallocN(sizeof(struct EDBMBaseOffset) * bases_len, + __func__); + sel_id_ctx->bases = bases; + sel_id_ctx->bases_len = bases_len; - MEM_freeN(buf); - return true; + edbm_select_pick_draw_bases(sel_id_ctx, vc, select_mode); + + return sel_id_ctx; +} + +void EDBM_select_id_context_destroy(struct EDBMSelectID_Context *sel_id_ctx) +{ + MEM_freeN(sel_id_ctx->base_array_index_offsets); + MEM_freeN(sel_id_ctx); } /** \} */ @@ -470,29 +458,44 @@ static void findnearestvert__doClosest(void *userData, BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, float *r_dist, const bool use_select_bias, - bool use_cycle) + bool use_cycle, + Base **bases, + uint bases_len, + uint *r_base_index) { - BMesh *bm = vc->em->bm; + uint base_index = 0; if (!XRAY_FLAG_ENABLED(vc->v3d)) { uint dist_px = (uint)ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist); - unsigned int index; + uint index; BMVert *eve; /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ { - FAKE_SELECT_MODE_BEGIN (vc, fake_select_mode, select_mode, SCE_SELECT_VERTEX) - ; - ED_view3d_select_id_validate_with_select_mode(vc, select_mode); + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_VERTEX); + + struct EDBMSelectID_Context *sel_id_ctx = EDBM_select_id_context_create( + vc, bases, bases_len, select_mode); + + index = ED_select_buffer_find_nearest_to_point(vc->mval, 1, UINT_MAX, &dist_px); + + if (index) { + eve = (BMVert *)EDBM_select_id_bm_elem_get(sel_id_ctx, index, &base_index); + } + else { + eve = NULL; + } - index = ED_view3d_select_id_read_nearest(vc, vc->mval, bm_wireoffs, 0xFFFFFF, &dist_px); - eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL; + EDBM_select_id_context_destroy(sel_id_ctx); FAKE_SELECT_MODE_END(vc, fake_select_mode); } if (eve) { if (dist_px < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } *r_dist = dist_px; return eve; } @@ -503,32 +506,52 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, struct NearestVertUserData data = {{0}}; const struct NearestVertUserData_Hit *hit; const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT; + BMesh *prev_select_bm = NULL; - static int prev_select_index = 0; - static const BMVert *prev_select_elem = NULL; - - if ((use_cycle == false) || - (prev_select_elem && - (prev_select_elem != BM_vert_at_index_find_or_table(bm, prev_select_index)))) { - prev_select_index = 0; - prev_select_elem = NULL; - } + static struct { + int index; + const BMVert *elem; + const BMesh *bm; + } prev_select = {0}; data.mval_fl[0] = vc->mval[0]; data.mval_fl[1] = vc->mval[1]; data.use_select_bias = use_select_bias; data.use_cycle = use_cycle; - data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; - data.cycle_index_prev = prev_select_index; - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag); + for (; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + ED_view3d_viewcontext_init_object(vc, base_iter->object); + if (use_cycle && prev_select.bm == vc->em->bm && + prev_select.elem == BM_vert_at_index_find_or_table(vc->em->bm, prev_select.index)) { + data.cycle_index_prev = prev_select.index; + /* No need to compare in the rest of the loop. */ + use_cycle = false; + } + else { + data.cycle_index_prev = 0; + } - hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit; - *r_dist = hit->dist; + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = + *r_dist; - prev_select_elem = hit->vert; - prev_select_index = hit->index; + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag); + + hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit; + + if (hit->dist < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } + *r_dist = hit->dist; + prev_select_bm = vc->em->bm; + } + } + + prev_select.index = hit->index; + prev_select.elem = hit->vert; + prev_select.bm = prev_select_bm; return hit->vert; } @@ -536,7 +559,8 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist) { - return EDBM_vert_find_nearest_ex(vc, r_dist, false, false); + Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); + return EDBM_vert_find_nearest_ex(vc, r_dist, false, false, &base, 1, NULL); } /* find the distance to the edge we already have */ @@ -658,24 +682,36 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, float *r_dist, float *r_dist_center, const bool use_select_bias, - const bool use_cycle, - BMEdge **r_eed_zbuf) + bool use_cycle, + BMEdge **r_eed_zbuf, + Base **bases, + uint bases_len, + uint *r_base_index) { - BMesh *bm = vc->em->bm; + uint base_index = 0; if (!XRAY_FLAG_ENABLED(vc->v3d)) { uint dist_px = (uint)ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist); - unsigned int index; + uint index; BMEdge *eed; /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ { - FAKE_SELECT_MODE_BEGIN (vc, fake_select_mode, select_mode, SCE_SELECT_EDGE) - ; - ED_view3d_select_id_validate_with_select_mode(vc, select_mode); + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_EDGE); + + struct EDBMSelectID_Context *sel_id_ctx = EDBM_select_id_context_create( + vc, bases, bases_len, select_mode); + + index = ED_select_buffer_find_nearest_to_point(vc->mval, 1, UINT_MAX, &dist_px); + + if (index) { + eed = (BMEdge *)EDBM_select_id_bm_elem_get(sel_id_ctx, index, &base_index); + } + else { + eed = NULL; + } - index = ED_view3d_select_id_read_nearest(vc, vc->mval, bm_solidoffs, bm_wireoffs, &dist_px); - eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL; + EDBM_select_id_context_destroy(sel_id_ctx); FAKE_SELECT_MODE_END(vc, fake_select_mode); } @@ -704,6 +740,9 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, if (eed) { if (dist_px < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } *r_dist = dist_px; return eed; } @@ -715,36 +754,57 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, const struct NearestEdgeUserData_Hit *hit; /* interpolate along the edge before doing a clipping plane test */ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB; + BMesh *prev_select_bm = NULL; - static int prev_select_index = 0; - static const BMEdge *prev_select_elem = NULL; - - if ((use_cycle == false) || - (prev_select_elem && - (prev_select_elem != BM_edge_at_index_find_or_table(bm, prev_select_index)))) { - prev_select_index = 0; - prev_select_elem = NULL; - } + static struct { + int index; + const BMEdge *elem; + const BMesh *bm; + } prev_select = {0}; data.vc = *vc; data.mval_fl[0] = vc->mval[0]; data.mval_fl[1] = vc->mval[1]; data.use_select_bias = use_select_bias; data.use_cycle = use_cycle; - data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; - data.cycle_index_prev = prev_select_index; - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag); + for (; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + ED_view3d_viewcontext_init_object(vc, base_iter->object); + if (use_cycle && prev_select.bm == vc->em->bm && + prev_select.elem == BM_edge_at_index_find_or_table(vc->em->bm, prev_select.index)) { + data.cycle_index_prev = prev_select.index; + /* No need to compare in the rest of the loop. */ + use_cycle = false; + } + else { + data.cycle_index_prev = 0; + } + + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = + *r_dist; + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag); + + hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit; + + if (hit->dist < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } + *r_dist = hit->dist; + prev_select_bm = vc->em->bm; + } + } - hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit; - *r_dist = hit->dist; if (r_dist_center) { *r_dist_center = hit->dist_center; } - prev_select_elem = hit->edge; - prev_select_index = hit->index; + prev_select.index = hit->index; + prev_select.elem = hit->edge; + prev_select.bm = prev_select_bm; return hit->edge; } @@ -752,7 +812,8 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *r_dist) { - return EDBM_edge_find_nearest_ex(vc, r_dist, NULL, false, false, NULL); + Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); + return EDBM_edge_find_nearest_ex(vc, r_dist, NULL, false, false, NULL, &base, 1, NULL); } /* find the distance to the face we already have */ @@ -831,23 +892,35 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, float *r_dist, float *r_dist_center, const bool use_select_bias, - const bool use_cycle, - BMFace **r_efa_zbuf) + bool use_cycle, + BMFace **r_efa_zbuf, + Base **bases, + uint bases_len, + uint *r_base_index) { - BMesh *bm = vc->em->bm; + uint base_index = 0; if (!XRAY_FLAG_ENABLED(vc->v3d)) { float dist_test = 0.0f; - unsigned int index; + uint index; BMFace *efa; { - FAKE_SELECT_MODE_BEGIN (vc, fake_select_mode, select_mode, SCE_SELECT_FACE) - ; - ED_view3d_select_id_validate_with_select_mode(vc, select_mode); + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_FACE); + + struct EDBMSelectID_Context *sel_id_ctx = EDBM_select_id_context_create( + vc, bases, bases_len, select_mode); + + index = ED_select_buffer_sample_point(vc->mval); + + if (index) { + efa = (BMFace *)EDBM_select_id_bm_elem_get(sel_id_ctx, index, &base_index); + } + else { + efa = NULL; + } - index = ED_view3d_select_id_sample(vc, vc->mval[0], vc->mval[1]); - efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL; + EDBM_select_id_context_destroy(sel_id_ctx); FAKE_SELECT_MODE_END(vc, fake_select_mode); } @@ -876,6 +949,9 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, if (efa) { if (dist_test < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } *r_dist = dist_test; return efa; } @@ -886,35 +962,56 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, struct NearestFaceUserData data = {{0}}; const struct NearestFaceUserData_Hit *hit; const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT; + BMesh *prev_select_bm = NULL; - static int prev_select_index = 0; - static const BMFace *prev_select_elem = NULL; - - if ((use_cycle == false) || - (prev_select_elem && - (prev_select_elem != BM_face_at_index_find_or_table(bm, prev_select_index)))) { - prev_select_index = 0; - prev_select_elem = NULL; - } + static struct { + int index; + const BMFace *elem; + const BMesh *bm; + } prev_select = {0}; data.mval_fl[0] = vc->mval[0]; data.mval_fl[1] = vc->mval[1]; data.use_select_bias = use_select_bias; data.use_cycle = use_cycle; - data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; - data.cycle_index_prev = prev_select_index; - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag); + for (; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + ED_view3d_viewcontext_init_object(vc, base_iter->object); + if (use_cycle && prev_select.bm == vc->em->bm && + prev_select.elem == BM_face_at_index_find_or_table(vc->em->bm, prev_select.index)) { + data.cycle_index_prev = prev_select.index; + /* No need to compare in the rest of the loop. */ + use_cycle = false; + } + else { + data.cycle_index_prev = 0; + } + + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = + *r_dist; + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag); + + hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit; + + if (hit->dist < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } + *r_dist = hit->dist; + prev_select_bm = vc->em->bm; + } + } - hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit; - *r_dist = hit->dist; if (r_dist_center) { *r_dist_center = hit->dist; } - prev_select_elem = hit->face; - prev_select_index = hit->index; + prev_select.index = hit->index; + prev_select.elem = hit->face; + prev_select.bm = prev_select_bm; return hit->face; } @@ -922,7 +1019,8 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist) { - return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL); + Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); + return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL, &base, 1, NULL); } #undef FIND_NEAR_SELECT_BIAS @@ -965,75 +1063,63 @@ static bool unified_findnearest(ViewContext *vc, } f, f_zbuf; } hit = {{NULL}}; - /* TODO(campbell): perform selection as one pass - * instead of many smaller passes (which doesn't work for zbuf occlusion). */ - /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ - if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) { + if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_FACE)) { float dist_center = 0.0f; float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : NULL; - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *obedit = base_iter->object; - ED_view3d_viewcontext_init_object(vc, obedit); - BLI_assert(vc->em->selectmode == em->selectmode); - BMFace *efa_zbuf = NULL; - BMFace *efa_test = EDBM_face_find_nearest_ex( - vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf); - if (efa_test && dist_center_p) { - dist = min_ff(dist_margin, dist_center); - } - if (efa_test) { - hit.f.base_index = base_index; - hit.f.ele = efa_test; - } - if (efa_zbuf) { - hit.f_zbuf.base_index = base_index; - hit.f_zbuf.ele = efa_zbuf; - } - } /* bases */ + uint base_index = 0; + BMFace *efa_zbuf = NULL; + BMFace *efa_test = EDBM_face_find_nearest_ex( + vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf, bases, bases_len, &base_index); + + if (efa_test && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (efa_test) { + hit.f.base_index = base_index; + hit.f.ele = efa_test; + } + if (efa_zbuf) { + hit.f_zbuf.base_index = base_index; + hit.f_zbuf.ele = efa_zbuf; + } } if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) { float dist_center = 0.0f; float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL; - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *obedit = base_iter->object; - ED_view3d_viewcontext_init_object(vc, obedit); - BMEdge *eed_zbuf = NULL; - BMEdge *eed_test = EDBM_edge_find_nearest_ex( - vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf); - if (eed_test && dist_center_p) { - dist = min_ff(dist_margin, dist_center); - } - if (eed_test) { - hit.e.base_index = base_index; - hit.e.ele = eed_test; - } - if (eed_zbuf) { - hit.e_zbuf.base_index = base_index; - hit.e_zbuf.ele = eed_zbuf; - } - } /* bases */ + uint base_index = 0; + BMEdge *eed_zbuf = NULL; + BMEdge *eed_test = EDBM_edge_find_nearest_ex( + vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf, bases, bases_len, &base_index); + + if (eed_test && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (eed_test) { + hit.e.base_index = base_index; + hit.e.ele = eed_test; + } + if (eed_zbuf) { + hit.e_zbuf.base_index = base_index; + hit.e_zbuf.ele = eed_zbuf; + } } - if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) { - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *obedit = base_iter->object; - ED_view3d_viewcontext_init_object(vc, obedit); - BMVert *eve_test = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle); - if (eve_test) { - hit.v.base_index = base_index; - hit.v.ele = eve_test; - } - } /* bases */ + if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_VERTEX)) { + uint base_index = 0; + BMVert *eve_test = EDBM_vert_find_nearest_ex( + vc, &dist, true, use_cycle, bases, bases_len, &base_index); + + if (eve_test) { + hit.v.base_index = base_index; + hit.v.ele = eve_test; + } } /* return only one of 3 pointers, for frontbuffer redraws */ diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index cd9d046ae04..a1ebcff31aa 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -336,6 +336,7 @@ void MESH_OT_subdivide_edgering(wmOperatorType *ot) { /* identifiers */ ot->name = "Subdivide Edge-Ring"; + ot->description = "Subdivide perpendicular edges to the selected edge ring"; ot->idname = "MESH_OT_subdivide_edgering"; /* api callbacks */ @@ -1123,7 +1124,7 @@ static int edbm_mark_sharp_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; - if (bm->totedgesel == 0) { + if ((use_verts && bm->totvertsel == 0) || (!use_verts && bm->totedgesel == 0)) { continue; } @@ -6793,7 +6794,7 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot) /* identifiers */ ot->name = "Bridge Edge Loops"; - ot->description = "Make faces between two or more edge loops"; + ot->description = "Create a bridge of faces between two or more selected edge loops"; ot->idname = "MESH_OT_bridge_edge_loops"; /* api callbacks */ @@ -7686,6 +7687,7 @@ static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); @@ -8075,7 +8077,7 @@ void MESH_OT_point_normals(struct wmOperatorType *ot) ot->exec = edbm_point_normals_exec; ot->invoke = edbm_point_normals_invoke; ot->modal = edbm_point_normals_modal; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; ot->ui = edbm_point_normals_ui; ot->cancel = point_normals_free; @@ -8241,6 +8243,7 @@ static int normals_split_merge(bContext *C, const bool do_merge) BMEdge *e; BMIter eiter; + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm) : NULL; @@ -8286,7 +8289,7 @@ void MESH_OT_merge_normals(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_merge_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -8306,7 +8309,7 @@ void MESH_OT_split_normals(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_split_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -8344,6 +8347,7 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op) BMLoop *l, *l_curr, *l_first; BMIter fiter; + BKE_editmesh_ensure_autosmooth(em); bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; BKE_editmesh_lnorspace_update(em); @@ -8504,7 +8508,7 @@ void MESH_OT_average_normals(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_average_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; ot->ui = edbm_average_normals_ui; /* flags */ @@ -8567,6 +8571,7 @@ static int edbm_normals_tools_exec(bContext *C, wmOperator *op) const int mode = RNA_enum_get(op->ptr, "mode"); const bool absolute = RNA_boolean_get(op->ptr, "absolute"); + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; @@ -8723,7 +8728,7 @@ void MESH_OT_normals_tools(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_normals_tools_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; ot->ui = edbm_normals_tools_ui; /* flags */ @@ -8763,6 +8768,7 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op) const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp"); + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * bm->totvert, __func__); @@ -8828,6 +8834,7 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op) MEM_freeN(vnors); EDBM_update_generic(em, true, false); } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -8841,7 +8848,7 @@ void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_set_normals_from_faces_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -8858,6 +8865,7 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) BMLoop *l; BMIter fiter, liter; + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); @@ -8933,7 +8941,7 @@ void MESH_OT_smoothen_normals(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_smoothen_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -8953,7 +8961,6 @@ void MESH_OT_smoothen_normals(struct wmOperatorType *ot) static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; @@ -8972,7 +8979,7 @@ static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op) const int cd_prop_int_offset = CustomData_get_n_offset( &bm->pdata, CD_PROP_INT, cd_prop_int_index); - const int face_strength = scene->toolsettings->face_strength; + const int face_strength = RNA_enum_get(op->ptr, "face_strength"); const bool set = RNA_boolean_get(op->ptr, "set"); BM_mesh_elem_index_ensure(bm, BM_FACE); @@ -9001,6 +9008,13 @@ static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static const EnumPropertyItem prop_mesh_face_strength_types[] = { + {FACE_STRENGTH_WEAK, "WEAK", 0, "Weak", ""}, + {FACE_STRENGTH_MEDIUM, "MEDIUM", 0, "Medium", ""}, + {FACE_STRENGTH_STRONG, "STRONG", 0, "Strong", ""}, + {0, NULL, 0, NULL, NULL}, +}; + void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot) { /* identifiers */ @@ -9010,11 +9024,18 @@ void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_mod_weighted_strength_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ot->prop = RNA_def_boolean(ot->srna, "set", 0, "Set value", "Set Value of faces"); - RNA_def_property_flag(ot->prop, PROP_HIDDEN); + + ot->prop = RNA_def_enum( + ot->srna, + "face_strength", + prop_mesh_face_strength_types, + FACE_STRENGTH_MEDIUM, + "Face Strength", + "Strength to use for assigning or selecting face influence for weighted normal modifier"); } diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index ed5e6c39f85..102ce3efc22 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -274,7 +274,7 @@ void ED_operatormacros_mesh(void) ot = WM_operatortype_append_macro("MESH_OT_extrude_context_move", "Extrude Region and Move", - "Extrude context and move result", + "Extrude region together along the average normal", OPTYPE_UNDO | OPTYPE_REGISTER); otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_context"); otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); @@ -283,7 +283,7 @@ void ED_operatormacros_mesh(void) ot = WM_operatortype_append_macro("MESH_OT_extrude_region_shrink_fatten", "Extrude Region and Shrink/Fatten", - "Extrude along normals and move result", + "Extrude region together along local normals", OPTYPE_UNDO | OPTYPE_REGISTER); otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region"); otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_shrink_fatten"); @@ -292,7 +292,7 @@ void ED_operatormacros_mesh(void) ot = WM_operatortype_append_macro("MESH_OT_extrude_faces_move", "Extrude Individual Faces and Move", - "Extrude faces and move result", + "Extrude each individual face separately along local normals", OPTYPE_UNDO | OPTYPE_REGISTER); otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_faces_indiv"); otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_shrink_fatten"); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index c32fef42d27..41736fb9a14 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -61,6 +61,7 @@ #include "DEG_depsgraph_query.h" #include "ED_mesh.h" +#include "ED_select_buffer_utils.h" #include "ED_object.h" #include "ED_view3d.h" @@ -1109,18 +1110,16 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, } ED_view3d_viewcontext_init(C, &vc); + ED_view3d_select_id_validate(&vc); if (dist_px) { /* sample rect to increase chances of selecting, so that when clicking * on an edge in the backbuf, we can still select a face */ - - ED_view3d_select_id_validate(&vc); - - *r_index = ED_view3d_select_id_read_nearest(&vc, mval, 1, me->totpoly + 1, &dist_px); + *r_index = ED_select_buffer_find_nearest_to_point(mval, 1, me->totpoly + 1, &dist_px); } else { /* sample only on the exact position */ - *r_index = ED_view3d_select_id_sample(&vc, mval[0], mval[1]); + *r_index = ED_select_buffer_sample_point(mval); } if ((*r_index) == 0 || (*r_index) > (unsigned int)me->totpoly) { @@ -1291,19 +1290,17 @@ bool ED_mesh_pick_vert( } ED_view3d_viewcontext_init(C, &vc); + ED_view3d_select_id_validate(&vc); if (use_zbuf) { if (dist_px > 0) { /* sample rect to increase chances of selecting, so that when clicking * on an face in the backbuf, we can still select a vert */ - - ED_view3d_select_id_validate(&vc); - - *r_index = ED_view3d_select_id_read_nearest(&vc, mval, 1, me->totvert + 1, &dist_px); + *r_index = ED_select_buffer_find_nearest_to_point(mval, 1, me->totvert + 1, &dist_px); } else { /* sample only on the exact position */ - *r_index = ED_view3d_select_id_sample(&vc, mval[0], mval[1]); + *r_index = ED_select_buffer_sample_point(mval); } if ((*r_index) == 0 || (*r_index) > (uint)me->totvert) { diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 54143822b61..18ff7ae1a5e 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -738,7 +738,7 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese } const uint hit_object = hitresult & 0xFFFF; - if (vc.obedit->select_id != hit_object) { + if (vc.obedit->runtime.select_id != hit_object) { continue; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index f8a13579732..cb152cb4e49 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -113,6 +113,10 @@ #include "object_intern.h" +/* -------------------------------------------------------------------- */ +/** \name Local Enum Declarations + * \{ */ + /* this is an exact copy of the define in rna_light.c * kept here because of linking order. * Icons are only defined here */ @@ -161,7 +165,25 @@ static EnumPropertyItem lightprobe_type_items[] = { {0, NULL, 0, NULL, NULL}, }; -/************************** Exported *****************************/ +enum { + ALIGN_WORLD = 0, + ALIGN_VIEW, + ALIGN_CURSOR, +}; + +static const EnumPropertyItem align_options[] = { + {ALIGN_WORLD, "WORLD", 0, "World", "Align the new object to the world"}, + {ALIGN_VIEW, "VIEW", 0, "View", "Align the new object to the view"}, + {ALIGN_CURSOR, "CURSOR", 0, "3D Cursor", "Use the 3D cursor orientation for the new object"}, + {0, NULL, 0, NULL, NULL}, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public Add Object API + * + * \{ */ void ED_object_location_from_view(bContext *C, float loc[3]) { @@ -266,7 +288,11 @@ float ED_object_new_primitive_matrix( // return 1.0f; } -/********************* Add Object Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Object Operator + * \{ */ static void view_align_update(struct Main *UNUSED(main), struct Scene *UNUSED(scene), @@ -291,16 +317,15 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode) { PropertyRNA *prop; - /* note: this property gets hidden for add-camera operator */ - prop = RNA_def_boolean( - ot->srna, "view_align", 0, "Align to View", "Align the new object to the view"); - RNA_def_property_update_runtime(prop, view_align_update); - if (do_editmode) { prop = RNA_def_boolean( ot->srna, "enter_editmode", 0, "Enter Editmode", "Enter editmode when adding this object"); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } + /* note: this property gets hidden for add-camera operator */ + prop = RNA_def_enum( + ot->srna, "align", align_options, ALIGN_WORLD, "Align", "The alignment of the new object"); + RNA_def_property_update_runtime(prop, view_align_update); prop = RNA_def_float_vector_xyz(ot->srna, "location", @@ -392,23 +417,44 @@ bool ED_object_add_generic_get_opts(bContext *C, rot = _rot; } + prop = RNA_struct_find_property(op->ptr, "align"); + int alignment = RNA_property_enum_get(op->ptr, prop); + bool alignment_set = RNA_property_is_set(op->ptr, prop); + if (RNA_struct_property_is_set(op->ptr, "rotation")) { *is_view_aligned = false; } - else if (RNA_struct_property_is_set(op->ptr, "view_align")) { - *is_view_aligned = RNA_boolean_get(op->ptr, "view_align"); + else if (alignment_set) { + *is_view_aligned = alignment == ALIGN_VIEW; } else { *is_view_aligned = (U.flag & USER_ADD_VIEWALIGNED) != 0; - RNA_boolean_set(op->ptr, "view_align", *is_view_aligned); + if (*is_view_aligned) { + RNA_property_enum_set(op->ptr, prop, ALIGN_VIEW); + alignment = ALIGN_VIEW; + } + else if (U.flag & USER_ADD_CURSORALIGNED) { + RNA_property_enum_set(op->ptr, prop, ALIGN_CURSOR); + alignment = ALIGN_CURSOR; + } } - if (*is_view_aligned) { - ED_object_rotation_from_view(C, rot, view_align_axis); - RNA_float_set_array(op->ptr, "rotation", rot); - } - else { - RNA_float_get_array(op->ptr, "rotation", rot); + switch (alignment) { + case ALIGN_WORLD: + RNA_float_get_array(op->ptr, "rotation", rot); + break; + case ALIGN_VIEW: + ED_object_rotation_from_view(C, rot, view_align_axis); + RNA_float_set_array(op->ptr, "rotation", rot); + break; + case ALIGN_CURSOR: { + const Scene *scene = CTX_data_scene(C); + float tmat[3][3]; + BKE_scene_cursor_rot_to_mat3(&scene->cursor, tmat); + mat3_normalized_to_eul(rot, tmat); + RNA_float_set_array(op->ptr, "rotation", rot); + break; + } } } @@ -516,7 +562,11 @@ void OBJECT_OT_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************** Add Probe Operator **********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Probe Operator + * \{ */ /* for object add operator */ static const char *get_lightprobe_defname(int type) @@ -604,7 +654,11 @@ void OBJECT_OT_lightprobe_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************* Add Effector Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Effector Operator + * \{ */ /* for object add operator */ static int effector_add_exec(bContext *C, wmOperator *op) @@ -677,7 +731,11 @@ void OBJECT_OT_effector_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************* Add Camera Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Camera Operator + * \{ */ static int object_camera_add_exec(bContext *C, wmOperator *op) { @@ -690,7 +748,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; /* force view align for cameras */ - RNA_boolean_set(op->ptr, "view_align", true); + RNA_enum_set(op->ptr, "align", ALIGN_VIEW); if (!ED_object_add_generic_get_opts( C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { @@ -732,11 +790,15 @@ void OBJECT_OT_camera_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); /* hide this for cameras, default */ - prop = RNA_struct_type_find_property(ot->srna, "view_align"); + prop = RNA_struct_type_find_property(ot->srna, "align"); RNA_def_property_flag(prop, PROP_HIDDEN); } -/********************* Add Metaball Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Metaball Operator + * \{ */ static int object_metaball_add_exec(bContext *C, wmOperator *op) { @@ -797,7 +859,11 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************* Add Text Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Text Operator + * \{ */ static int object_add_text_exec(bContext *C, wmOperator *op) { @@ -842,7 +908,11 @@ void OBJECT_OT_text_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************* Add Armature Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Armature Operator + * \{ */ static int object_armature_add_exec(bContext *C, wmOperator *op) { @@ -905,7 +975,11 @@ void OBJECT_OT_armature_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************* Add Empty Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Empty Operator + * \{ */ static int object_empty_add_exec(bContext *C, wmOperator *op) { @@ -1025,7 +1099,12 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot) ED_object_add_generic_props(ot, false); } -/********************* Add Gpencil Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Gpencil Operator + * \{ */ + static bool object_gpencil_add_poll(bContext *C) { Scene *scene = CTX_data_scene(C); @@ -1156,7 +1235,11 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", ""); } -/********************* Add Light Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Light Operator + * \{ */ static const char *get_light_defname(int type) { @@ -1176,7 +1259,6 @@ static const char *get_light_defname(int type) static int object_light_add_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); Object *ob; Light *la; int type = RNA_enum_get(op->ptr, "type"); @@ -1207,9 +1289,8 @@ static int object_light_add_exec(bContext *C, wmOperator *op) la = (Light *)ob->data; la->type = type; - if (BKE_scene_uses_cycles(scene)) { - ED_node_shader_default(C, &la->id); - la->use_nodes = true; + if (type == LA_SUN) { + la->energy = 1.0f; } return OPERATOR_FINISHED; @@ -1238,7 +1319,11 @@ void OBJECT_OT_light_add(wmOperatorType *ot) ED_object_add_generic_props(ot, false); } -/********************* Add Collection Instance Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Collection Instance Operator + * \{ */ static int collection_instance_add_exec(bContext *C, wmOperator *op) { @@ -1324,7 +1409,11 @@ void OBJECT_OT_collection_instance_add(wmOperatorType *ot) ED_object_add_generic_props(ot, false); } -/********************* Add Speaker Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Speaker Operator + * \{ */ static int object_speaker_add_exec(bContext *C, wmOperator *op) { @@ -1379,7 +1468,11 @@ void OBJECT_OT_speaker_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/**************************** Delete Object *************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Object Operator + * \{ */ /* remove base from a specific scene */ /* note: now unlinks constraints as well */ @@ -1537,7 +1630,11 @@ void OBJECT_OT_delete(wmOperatorType *ot) WM_operator_properties_confirm_or_exec(ot); } -/**************************** Copy Utilities ******************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Copy Object Utilities + * \{ */ /* after copying objects, copied data should get new pointers */ static void copy_object_set_idnew(bContext *C) @@ -1552,7 +1649,11 @@ static void copy_object_set_idnew(bContext *C) BKE_main_id_clear_newpoins(bmain); } -/********************* Make Duplicates Real ************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Make Instanced Objects Real Operator + * \{ */ /** * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION, @@ -1656,7 +1757,7 @@ static void make_object_duplilist_real( for (dob = lb_duplis->first; dob; dob = dob->next) { Object *ob_src = DEG_get_original_object(dob->ob); - Object *ob_dst = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, ob_src)); + Object *ob_dst = ID_NEW_SET(ob_src, BKE_object_copy(bmain, ob_src)); Base *base_dst; /* font duplis can have a totcol without material, we get them from parent @@ -1838,7 +1939,11 @@ void OBJECT_OT_duplicates_make_real(wmOperatorType *ot) ot->srna, "use_hierarchy", 0, "Keep Hierarchy", "Maintain parent child relationships"); } -/**************************** Convert **************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Data Convert Operator + * \{ */ static const EnumPropertyItem convert_target_items[] = { {OB_CURVE, "CURVE", ICON_OUTLINER_OB_CURVE, "Curve from Mesh/Text", ""}, @@ -1857,7 +1962,7 @@ static void convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Objec if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { /* We need 'for render' ON here, to enable computing bevel dipslist if needed. * Also makes sense anyway, we would not want e.g. to loose hidden parts etc. */ - BKE_displist_make_curveTypes(depsgraph, scene, ob, true, false, NULL); + BKE_displist_make_curveTypes(depsgraph, scene, ob, true, false); } else if (ob->type == OB_MBALL) { BKE_displist_make_mball(depsgraph, scene, ob); @@ -1947,7 +2052,8 @@ static int convert_exec(bContext *C, wmOperator *op) FOREACH_SCENE_OBJECT_END; } - ListBase selected_editable_bases = CTX_data_collection_get(C, "selected_editable_bases"); + ListBase selected_editable_bases; + CTX_data_selected_editable_bases(C, &selected_editable_bases); /* Ensure we get all meshes calculated with a sufficient data-mask, * needed since re-evaluating single modifiers causes bugs if they depend @@ -2293,7 +2399,11 @@ void OBJECT_OT_convert(wmOperatorType *ot) "Keep original objects instead of replacing them"); } -/**************************** Duplicate ************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Duplicate Object Operator + * \{ */ /* * dupflag: a flag made from constants declared in DNA_userdef_types.h @@ -2449,7 +2559,13 @@ void OBJECT_OT_duplicate(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -/* **************** add named object, for dragdrop ************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Named Object Operator + * + * Use for for drag & drop. + * \{ */ static int add_named_exec(bContext *C, wmOperator *op) { @@ -2481,7 +2597,7 @@ static int add_named_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - basen->object->restrictflag &= ~OB_RESTRICT_VIEW; + basen->object->restrictflag &= ~OB_RESTRICT_VIEWPORT; if (event) { ARegion *ar = CTX_wm_region(C); @@ -2527,7 +2643,12 @@ void OBJECT_OT_add_named(wmOperatorType *ot) RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Object name to add"); } -/**************************** Join *************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Join Object Operator + * + * \{ */ static bool join_poll(bContext *C) { @@ -2596,7 +2717,11 @@ void OBJECT_OT_join(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/**************************** Join as Shape Key*************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Join as Shape Key Operator + * \{ */ static bool join_shapes_poll(bContext *C) { @@ -2649,3 +2774,5 @@ void OBJECT_OT_join_shapes(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/** \} */ diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 5ae757cac56..f87342a14ad 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -277,7 +277,8 @@ static bool write_internal_bake_pixels(Image *image, RE_bake_margin(ibuf, mask_buffer, margin); } - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID | IB_BITMAPDIRTY; + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + BKE_image_mark_dirty(image, ibuf); if (ibuf->rect_float) { ibuf->userflags |= IB_RECT_INVALID; @@ -704,10 +705,9 @@ static size_t initialize_internal_images(BakeImages *bake_images, ReportList *re } /* create new mesh with edit mode changes and modifiers applied */ -static Mesh *bake_mesh_new_from_object(Depsgraph *depsgraph, Main *bmain, Scene *scene, Object *ob) +static Mesh *bake_mesh_new_from_object(Object *object) { - bool apply_modifiers = (ob->type != OB_MESH); - Mesh *me = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob, apply_modifiers, false); + Mesh *me = BKE_object_to_mesh(object); if (me->flag & ME_AUTOSMOOTH) { BKE_mesh_split_faces(me, true); @@ -903,7 +903,7 @@ static int bake(Render *re, ob_low_eval = DEG_get_evaluated_object(depsgraph, ob_low); /* get the mesh as it arrives in the renderer */ - me_low = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval); + me_low = bake_mesh_new_from_object(ob_low_eval); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) { @@ -917,7 +917,7 @@ static int bake(Render *re, /* prepare cage mesh */ if (ob_cage) { - me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_cage_eval); + me_cage = bake_mesh_new_from_object(ob_cage_eval); if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { BKE_report(reports, RPT_ERROR, @@ -946,7 +946,7 @@ static int bake(Render *re, md = md_next; } - me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval); + me_cage = BKE_object_to_mesh(ob_low_eval); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } @@ -965,7 +965,7 @@ static int bake(Render *re, highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER; highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER); - highpoly[i].me = bake_mesh_new_from_object(depsgraph, bmain, scene, highpoly[i].ob_eval); + highpoly[i].me = BKE_object_to_mesh(highpoly[i].ob_eval); /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); @@ -1088,7 +1088,7 @@ static int bake(Render *re, } /* Evaluate modifiers again. */ - me_nores = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval, true, false); + me_nores = BKE_object_to_mesh(ob_low_eval); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, @@ -1098,7 +1098,7 @@ static int bake(Render *re, me_nores, normal_swizzle, ob_low_eval->obmat); - BKE_id_free(bmain, me_nores); + BKE_object_to_mesh_clear(ob_low_eval); if (md) { md->mode = mode; @@ -1222,7 +1222,7 @@ cleanup: int i; for (i = 0; i < tot_highpoly; i++) { if (highpoly[i].me) { - BKE_id_free(bmain, highpoly[i].me); + BKE_object_to_mesh_clear(highpoly[i].ob_eval); } } MEM_freeN(highpoly); @@ -1253,11 +1253,11 @@ cleanup: } if (me_low) { - BKE_id_free(bmain, me_low); + BKE_object_to_mesh_clear(ob_low_eval); } if (me_cage) { - BKE_id_free(bmain, me_cage); + BKE_object_to_mesh_clear(ob_cage_eval); } DEG_graph_free(depsgraph); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 6a587bd6e2a..abdf64af595 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -160,7 +160,7 @@ static void validate_pyconstraint_cb(Main *bmain, void *arg1, void *arg2) if (index) { /* innovative use of a for...loop to search */ for (text = bmain->texts.first, i = 1; text && index != i; i++, text = text->id.next) { - ; + /* pass */ } } data->text = text; @@ -1878,14 +1878,6 @@ static int constraint_add_exec( if (type == CONSTRAINT_TYPE_NULL) { return OPERATOR_CANCELLED; } - if ((type == CONSTRAINT_TYPE_KINEMATIC) && ((!pchan) || (list != &pchan->constraints))) { - BKE_report(op->reports, RPT_ERROR, "IK constraint can only be added to bones"); - return OPERATOR_CANCELLED; - } - if ((type == CONSTRAINT_TYPE_SPLINEIK) && ((!pchan) || (list != &pchan->constraints))) { - BKE_report(op->reports, RPT_ERROR, "Spline IK constraint can only be added to bones"); - return OPERATOR_CANCELLED; - } /* Create a new constraint of the type required, * and add it to the active/given constraints list. */ @@ -2023,8 +2015,33 @@ static int pose_constraint_add_exec(bContext *C, wmOperator *op) /* ------------------ */ +/* Filters constraints that are only compatible with bones */ +static const EnumPropertyItem *object_constraint_add_itemf(bContext *UNUSED(C), + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + const EnumPropertyItem *item = rna_enum_constraint_type_items; + EnumPropertyItem *object_constraint_items = NULL; + int totitem = 0; + + while (item->identifier) { + if ((item->value != CONSTRAINT_TYPE_KINEMATIC) && (item->value != CONSTRAINT_TYPE_SPLINEIK)) { + RNA_enum_item_add(&object_constraint_items, &totitem, item); + } + item++; + } + + RNA_enum_item_end(&object_constraint_items, &totitem); + *r_free = true; + + return object_constraint_items; +} + void OBJECT_OT_constraint_add(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Add Constraint"; ot->description = "Add a constraint to the active object"; @@ -2039,11 +2056,15 @@ void OBJECT_OT_constraint_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); + prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Type", ""); + RNA_def_enum_funcs(prop, object_constraint_add_itemf); + ot->prop = prop; } void OBJECT_OT_constraint_add_with_targets(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Add Constraint (with Targets)"; ot->description = @@ -2060,7 +2081,9 @@ void OBJECT_OT_constraint_add_with_targets(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); + prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Type", ""); + RNA_def_enum_funcs(prop, object_constraint_add_itemf); + ot->prop = prop; } void POSE_OT_constraint_add(wmOperatorType *ot) diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 795e1dd66a5..a542911f4d4 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -314,7 +314,7 @@ void ED_collection_hide_menu_draw(const bContext *C, uiLayout *layout) continue; } - if (lc->collection->flag & COLLECTION_RESTRICT_VIEW) { + if (lc->collection->flag & COLLECTION_RESTRICT_VIEWPORT) { continue; } @@ -722,7 +722,7 @@ static bool editmode_toggle_poll(bContext *C) } /* if hidden but in edit mode, we still display */ - if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) { + if ((ob->restrictflag & OB_RESTRICT_VIEWPORT) && !(ob->mode & OB_MODE_EDIT)) { return 0; } @@ -1779,4 +1779,5 @@ void OBJECT_OT_link_to_collection(wmOperatorType *ot) "Name", "Name of the newly added collection"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + ot->prop = prop; } diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index e555f0d940d..8d3a636671a 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -108,7 +108,7 @@ static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object * BKE_displist_make_mball(depsgraph, scene_eval, ob_eval); } else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false, false, NULL); + BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false, false); } } diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index e15d85a7953..6df012cdc80 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -697,7 +697,7 @@ bool ED_object_parent_set(ReportList *reports, cu->flag |= CU_PATH | CU_FOLLOW; cu_eval->flag |= CU_PATH | CU_FOLLOW; /* force creation of path data */ - BKE_displist_make_curveTypes(depsgraph, scene, par, false, false, NULL); + BKE_displist_make_curveTypes(depsgraph, scene, par, false, false); } else { cu->flag |= CU_FOLLOW; diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index cb8fe262730..40b7a245f69 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -47,6 +47,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "ED_mesh.h" #include "ED_screen.h" @@ -360,6 +361,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) DynamicPaintSurface *surface = job->surface; Object *cObject = job->ob; DynamicPaintCanvasSettings *canvas = surface->canvas; + Scene *input_scene = DEG_get_input_scene(job->depsgraph); Scene *scene = job->scene; int frame = 1, orig_frame; int frames; @@ -375,8 +377,8 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) /* Set frame to start point (also inits modifier data) */ frame = surface->start_frame; - orig_frame = scene->r.cfra; - scene->r.cfra = (int)frame; + orig_frame = input_scene->r.cfra; + input_scene->r.cfra = (int)frame; ED_update_for_newframe(job->bmain, job->depsgraph); /* Init surface */ @@ -402,7 +404,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) *(job->progress) = progress; /* calculate a frame */ - scene->r.cfra = (int)frame; + input_scene->r.cfra = (int)frame; ED_update_for_newframe(job->bmain, job->depsgraph); if (!dynamicPaint_calculateFrame(surface, job->depsgraph, scene, cObject, frame)) { job->success = 0; @@ -438,7 +440,8 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) } } - scene->r.cfra = orig_frame; + input_scene->r.cfra = orig_frame; + ED_update_for_newframe(job->bmain, job->depsgraph); } static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update, float *progress) @@ -470,25 +473,26 @@ static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update */ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op) { - DynamicPaintModifierData *pmd = NULL; - DynamicPaintCanvasSettings *canvas; - Object *ob = ED_object_context(C); - Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob_ = ED_object_context(C); + Object *object_eval = DEG_get_evaluated_object(depsgraph, ob_); + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); DynamicPaintSurface *surface; /* * Get modifier data */ - pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint); - if (!pmd) { + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType( + object_eval, eModifierType_DynamicPaint); + if (pmd == NULL) { BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found"); return OPERATOR_CANCELLED; } /* Make sure we're dealing with a canvas */ - canvas = pmd->canvas; - if (!canvas) { + DynamicPaintCanvasSettings *canvas = pmd->canvas; + if (canvas == NULL) { BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas"); return OPERATOR_CANCELLED; } @@ -500,15 +504,15 @@ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op) DynamicPaintBakeJob *job = MEM_mallocN(sizeof(DynamicPaintBakeJob), "DynamicPaintBakeJob"); job->bmain = CTX_data_main(C); - job->scene = scene; + job->scene = scene_eval; job->depsgraph = CTX_data_depsgraph(C); - job->ob = ob; + job->ob = object_eval; job->canvas = canvas; job->surface = surface; wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), - scene, + CTX_data_scene(C), "Dynamic Paint Bake", WM_JOB_PROGRESS, WM_JOB_TYPE_DPAINT_BAKE); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 09bcc0a3058..1e85c895f71 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -356,7 +356,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) /* cleanup sequencer caches before starting user triggered render. * otherwise, invalidated cache entries can make their way into - * the output rendering. We can't put that into RE_BlenderFrame, + * the output rendering. We can't put that into RE_RenderFrame, * since sequence rendering can call that recursively... (peter) */ BKE_sequencer_cache_cleanup(scene); @@ -364,18 +364,17 @@ static int screen_render_exec(bContext *C, wmOperator *op) BLI_threaded_malloc_begin(); if (is_animation) { - RE_BlenderAnim(re, - mainp, - scene, - single_layer, - camera_override, - scene->r.sfra, - scene->r.efra, - scene->r.frame_step); + RE_RenderAnim(re, + mainp, + scene, + single_layer, + camera_override, + scene->r.sfra, + scene->r.efra, + scene->r.frame_step); } else { - RE_BlenderFrame( - re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still); + RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still); } BLI_threaded_malloc_end(); @@ -671,23 +670,23 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro RE_SetReports(rj->re, rj->reports); if (rj->anim) { - RE_BlenderAnim(rj->re, + RE_RenderAnim(rj->re, + rj->main, + rj->scene, + rj->single_layer, + rj->camera_override, + rj->scene->r.sfra, + rj->scene->r.efra, + rj->scene->r.frame_step); + } + else { + RE_RenderFrame(rj->re, rj->main, rj->scene, rj->single_layer, rj->camera_override, - rj->scene->r.sfra, - rj->scene->r.efra, - rj->scene->r.frame_step); - } - else { - RE_BlenderFrame(rj->re, - rj->main, - rj->scene, - rj->single_layer, - rj->camera_override, - rj->scene->r.cfra, - rj->write_still); + rj->scene->r.cfra, + rj->write_still); } RE_SetReports(rj->re, NULL); @@ -976,7 +975,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* cleanup sequencer caches before starting user triggered render. * otherwise, invalidated cache entries can make their way into - * the output rendering. We can't put that into RE_BlenderFrame, + * the output rendering. We can't put that into RE_RenderFrame, * since sequence rendering can call that recursively... (peter) */ BKE_sequencer_cache_cleanup(scene); diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 28cfce00e6e..20229b63258 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -114,7 +114,6 @@ typedef struct OGLRender { GPUOffScreen *ofs; int ofs_samples; - bool ofs_full_samples; int sizex, sizey; int write_still; @@ -356,9 +355,6 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R ImBuf *ibuf_view; const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL; - unsigned int draw_flags = V3D_OFSDRAW_NONE; - draw_flags |= (oglrender->ofs_full_samples) ? V3D_OFSDRAW_USE_FULL_SAMPLE : 0; - if (view_context) { ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph, scene, @@ -368,7 +364,6 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R sizex, sizey, IB_rectfloat, - draw_flags, alpha_mode, oglrender->ofs_samples, viewname, @@ -381,7 +376,6 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R } } else { - draw_flags |= V3D_OFSDRAW_SHOW_ANNOTATION; ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(depsgraph, scene, NULL, @@ -390,7 +384,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R oglrender->sizex, oglrender->sizey, IB_rectfloat, - draw_flags, + V3D_OFSDRAW_SHOW_ANNOTATION, alpha_mode, oglrender->ofs_samples, viewname, @@ -489,8 +483,6 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) for (view_id = 0; view_id < oglrender->views_len; view_id++) { context.view_id = view_id; context.gpu_offscreen = oglrender->ofs; - context.gpu_full_samples = oglrender->ofs_full_samples; - oglrender->seq_data.ibufs_arr[view_id] = BKE_sequencer_give_ibuf(&context, CFRA, chanshown); } } @@ -517,24 +509,6 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) } } -static bool screen_opengl_fullsample_enabled(Scene *scene) -{ - if (scene->r.scemode & R_FULL_SAMPLE) { - return true; - } - else { - /* XXX TODO: - * Technically if the hardware supports MSAA we could keep using Blender 2.7x approach. - * However anti-aliasing without full_sample is not playing well even in 2.7x. - * - * For example, if you enable depth of field, there is aliasing, even if the viewport is fine. - * For 2.8x this is more complicated because so many things rely on shader. - * So until we fix the gpu_framebuffer anti-aliasing suupport we need to force full sample. - */ - return true; - } -} - static bool screen_opengl_render_init(bContext *C, wmOperator *op) { /* new render clears all callbacks */ @@ -548,12 +522,11 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) GPUOffScreen *ofs; OGLRender *oglrender; int sizex, sizey; - const int samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0; - const bool full_samples = (samples != 0) && screen_opengl_fullsample_enabled(scene); bool is_view_context = RNA_boolean_get(op->ptr, "view_context"); const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); + const int samples = U.ogl_multisamples; char err_out[256] = "unknown"; if (G.background) { @@ -598,7 +571,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) /* corrects render size with actual size, not every card supports non-power-of-two dimensions */ DRW_opengl_context_enable(); /* Offscreen creation needs to be done in DRW context. */ - ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, true, true, err_out); + ofs = GPU_offscreen_create(sizex, sizey, samples, true, true, err_out); DRW_opengl_context_disable(); if (!ofs) { @@ -611,8 +584,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) op->customdata = oglrender; oglrender->ofs = ofs; - oglrender->ofs_samples = samples; - oglrender->ofs_full_samples = full_samples; oglrender->sizex = sizex; oglrender->sizey = sizey; oglrender->bmain = CTX_data_main(C); @@ -621,6 +592,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) oglrender->view_layer = CTX_data_view_layer(C); oglrender->depsgraph = CTX_data_depsgraph(C); oglrender->cfrao = scene->r.cfra; + oglrender->ofs_samples = samples; oglrender->write_still = is_write_still && !is_animation; oglrender->is_animation = is_animation; diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index bf6d658f927..76b88b8df22 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -270,7 +270,7 @@ static const char *preview_collection_name(const char pr_type) case MA_FLUID: return "Fluid"; case MA_SPHERE_A: - return "World Shader Ball"; + return "World Sphere"; case MA_LAMP: return "Lamp"; case MA_SKY: @@ -437,7 +437,14 @@ static Scene *preview_prepare_scene( sce->world->horb = 0.05f; } - set_preview_visibility(sce, view_layer, mat->pr_type, sp->pr_method); + if (sp->pr_method == PR_ICON_RENDER && sp->pr_main == G_pr_main_grease_pencil) { + /* For grease pencil, always use sphere for icon renders. */ + set_preview_visibility(sce, view_layer, MA_SPHERE_A, sp->pr_method); + } + else { + /* Use specified preview shape for both preview panel and icon previews. */ + set_preview_visibility(sce, view_layer, mat->pr_type, sp->pr_method); + } if (sp->pr_method != PR_ICON_RENDER) { if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) { @@ -449,7 +456,7 @@ static Scene *preview_prepare_scene( } } else { - sce->r.mode &= ~(R_OSA); + sce->display.render_aa = SCE_DISPLAY_AA_OFF; } for (Base *base = view_layer->object_bases.first; base; base = base->next) { @@ -861,7 +868,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs if (sp->pr_method == PR_ICON_RENDER) { sce->r.scemode |= R_NO_IMAGE_LOAD; - sce->r.mode |= R_OSA; + sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8; } else if (sp->pr_method == PR_NODE_RENDER) { if (idtype == ID_MA) { @@ -870,10 +877,10 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs else if (idtype == ID_TE) { sce->r.scemode |= R_TEXNODE_PREVIEW; } - sce->r.mode &= ~R_OSA; + sce->display.render_aa = SCE_DISPLAY_AA_OFF; } else { /* PR_BUTS_RENDER */ - sce->r.mode |= R_OSA; + sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8; } /* callbacs are cleared on GetRender() */ @@ -969,7 +976,7 @@ static void shader_preview_free(void *customdata) /* get rid of copied ID */ properties = IDP_GetProperties(sp->id_copy, false); if (properties) { - IDP_FreeProperty_ex(properties, false); + IDP_FreePropertyContent_ex(properties, false); MEM_freeN(properties); } switch (GS(sp->id_copy->name)) { diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 3186f011c6a..f7a1d7187f1 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -595,7 +595,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&ma->id); RNA_id_pointer_create(&ma->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } @@ -644,7 +644,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&tex->id); RNA_id_pointer_create(&tex->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } @@ -695,7 +695,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&wo->id); RNA_id_pointer_create(&wo->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 3f3f98bc6e5..64869b71746 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -132,7 +132,10 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update CTX_wm_region_set(C, ar); engine->flag &= ~RE_ENGINE_DO_UPDATE; - engine->type->view_update(engine, C); + /* NOTE: Important to pass non-updated depsgraph, This is because this function is called + * from inside dependency graph evaluation. Additionally, if we pass fully evaluated one + * we will loose updates stored in the graph. */ + engine->type->view_update(engine, C, CTX_data_depsgraph(C)); } else { RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type); @@ -265,7 +268,7 @@ static void image_changed(Main *bmain, Image *ima) /* textures */ for (tex = bmain->textures.first; tex; tex = tex->id.next) { - if (tex->ima == ima) { + if (tex->type == TEX_IMAGE && tex->ima == ima) { texture_changed(bmain, tex); } } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 38684afec39..9b35c809d5a 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -50,6 +50,7 @@ #include "ED_screen.h" #include "ED_screen_types.h" #include "ED_space_api.h" +#include "ED_time_scrub_ui.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" @@ -202,7 +203,7 @@ static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, f alpha = min_ff(alpha, 0.75f); - UI_icon_draw_aspect(x, y, ICON_FULLSCREEN_EXIT, 0.7f / UI_DPI_FAC, alpha, NULL); + UI_icon_draw_ex(x, y, ICON_FULLSCREEN_EXIT, 0.7f * U.inv_dpi_fac, 0.0f, alpha, NULL, false); /* debug drawing : * The click_rect is the same as defined in fullscreen_click_rcti_init @@ -457,19 +458,6 @@ void ED_area_do_msg_notify_tag_refresh( ED_area_tag_refresh(sa); } -static void region_do_msg_notify_tag_redraw( - /* Follow wmMsgNotifyFn spec */ - bContext *UNUSED(C), - wmMsgSubscribeKey *UNUSED(msg_key), - wmMsgSubscribeValue *msg_val) -{ - ARegion *ar = msg_val->owner; - ED_region_tag_redraw(ar); - - /* FIXME(campbell): shouldn't be needed. */ - WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL); -} - void ED_area_do_mgs_subscribe_for_tool_header( /* Follow ARegionType.message_subscribe */ const struct bContext *UNUSED(C), @@ -480,18 +468,39 @@ void ED_area_do_mgs_subscribe_for_tool_header( struct ARegion *ar, struct wmMsgBus *mbus) { + BLI_assert(ar->regiontype == RGN_TYPE_TOOL_HEADER); wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { .owner = ar, .user_data = ar, - /* TODO(campbell): investigate why - * ED_region_do_msg_notify_tag_redraw doesn't work here. */ - // .notify = ED_region_do_msg_notify_tag_redraw, - .notify = region_do_msg_notify_tag_redraw, + .notify = ED_region_do_msg_notify_tag_redraw, }; WM_msg_subscribe_rna_prop( mbus, &workspace->id, workspace, WorkSpace, tools, &msg_sub_value_region_tag_redraw); } +void ED_area_do_mgs_subscribe_for_tool_ui( + /* Follow ARegionType.message_subscribe */ + const struct bContext *UNUSED(C), + struct WorkSpace *workspace, + struct Scene *UNUSED(scene), + struct bScreen *UNUSED(screen), + struct ScrArea *UNUSED(sa), + struct ARegion *ar, + struct wmMsgBus *mbus) +{ + BLI_assert(ar->regiontype == RGN_TYPE_UI); + const char *category = UI_panel_category_active_get(ar, false); + if (category && STREQ(category, "Tool")) { + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + WM_msg_subscribe_rna_prop( + mbus, &workspace->id, workspace, WorkSpace, tools, &msg_sub_value_region_tag_redraw); + } +} + /** * Although there's no general support for minimizing areas, the status-bar can * be snapped to be only a few pixels high. A few pixels rather than 0 so it @@ -1050,11 +1059,11 @@ static void region_azones_scrollbars_initialize(ScrArea *sa, ARegion *ar) { const View2D *v2d = &ar->v2d; - if ((v2d->scroll & V2D_SCROLL_VERTICAL) && ((v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) == 0)) { + if ((v2d->scroll & V2D_SCROLL_VERTICAL) && ((v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) == 0)) { region_azone_scrollbar_initialize(sa, ar, AZ_SCROLL_VERT); } if ((v2d->scroll & V2D_SCROLL_HORIZONTAL) && - ((v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) == 0)) { + ((v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) == 0)) { region_azone_scrollbar_initialize(sa, ar, AZ_SCROLL_HOR); } } @@ -1110,7 +1119,7 @@ static int rct_fits(const rcti *rect, char dir, int size) static void region_overlap_fix(ScrArea *sa, ARegion *ar) { ARegion *ar1; - const int align = ar->alignment & ~RGN_SPLIT_PREV; + const int align = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment); int align1 = 0; /* find overlapping previous region on same place */ @@ -1227,7 +1236,7 @@ static void region_rect_recursive( } } - int alignment = ar->alignment & ~RGN_SPLIT_PREV; + int alignment = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment); /* set here, assuming userpref switching forces to call this again */ ar->overlap = ED_region_is_overlap(sa->spacetype, ar->regiontype); @@ -1596,14 +1605,19 @@ static void ed_default_handlers( wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } - if (flag & ED_KEYMAP_MARKERS) { + if (flag & ED_KEYMAP_ANIMATION) { + wmKeyMap *keymap; + /* time-markers */ - wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Markers", 0, 0); + keymap = WM_keymap_ensure(wm->defaultconf, "Markers", 0, 0); WM_event_add_keymap_handler_poll(handlers, keymap, event_in_markers_region); - } - if (flag & ED_KEYMAP_ANIMATION) { + + /* time-scrubbing */ + keymap = WM_keymap_ensure(wm->defaultconf, "Scrubbing", 0, 0); + WM_event_add_keymap_handler_poll(handlers, keymap, ED_event_in_scrubbing_region); + /* frame changing and timeline operators (for time spaces) */ - wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Animation", 0, 0); + keymap = WM_keymap_ensure(wm->defaultconf, "Animation", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } if (flag & ED_KEYMAP_FRAMES) { @@ -1613,14 +1627,19 @@ static void ed_default_handlers( } if (flag & ED_KEYMAP_HEADER) { /* standard keymap for headers regions */ - wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Header", 0, 0); + wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Region Context Menu", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } if (flag & ED_KEYMAP_FOOTER) { /* standard keymap for footer regions */ - wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Footer", 0, 0); + wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Region Context Menu", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } + if (flag & ED_KEYMAP_NAVBAR) { + /* standard keymap for Navigation bar regions */ + wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Region Context Menu", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + } /* Keep last because of LMB/RMB handling, see: T57527. */ if (flag & ED_KEYMAP_GPENCIL) { @@ -1690,7 +1709,7 @@ void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *ar } /* Some AZones use View2D data which is only updated in region init, so call that first! */ - region_azones_add(screen, area, ar, ar->alignment & ~RGN_SPLIT_PREV); + region_azones_add(screen, area, ar, RGN_ALIGN_ENUM_FROM_MASK(ar->alignment)); } ED_area_azones_update(area, &win->eventstate->x); @@ -1761,7 +1780,7 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa) } /* Some AZones use View2D data which is only updated in region init, so call that first! */ - region_azones_add(screen, sa, ar, ar->alignment & ~RGN_SPLIT_PREV); + region_azones_add(screen, sa, ar, RGN_ALIGN_ENUM_FROM_MASK(ar->alignment)); } /* Avoid re-initializing tools while resizing the window. */ @@ -2273,7 +2292,7 @@ static void ed_panel_draw(const bContext *C, } } - UI_panel_end(block, w, h); + UI_panel_end(block, w, h, open); } /** @@ -2281,34 +2300,62 @@ static void ed_panel_draw(const bContext *C, * Matching against any of these strings will draw the panel. * Can be NULL to skip context checks. */ -void ED_region_panels_layout_ex( - const bContext *C, ARegion *ar, const char *contexts[], int contextnr, const bool vertical) +void ED_region_panels_layout_ex(const bContext *C, + ARegion *ar, + ListBase *paneltypes, + const char *contexts[], + int contextnr, + const bool vertical, + const char *category_override) { + /* collect panels to draw */ + WorkSpace *workspace = CTX_wm_workspace(C); + LinkNode *panel_types_stack = NULL; + for (PanelType *pt = paneltypes->last; pt; pt = pt->prev) { + /* Only draw top level panels. */ + if (pt->parent) { + continue; + } + + if (category_override) { + if (!STREQ(pt->category, category_override)) { + continue; + } + } + + /* verify context */ + if (contexts && pt->context[0] && !streq_array_any(pt->context, contexts)) { + continue; + } + + /* If we're tagged, only use compatible. */ + if (pt->owner_id[0] && BKE_workspace_owner_id_check(workspace, pt->owner_id) == false) { + continue; + } + + /* draw panel */ + if (pt->draw && (!pt->poll || pt->poll(C, pt))) { + BLI_linklist_prepend_alloca(&panel_types_stack, pt); + } + } + ar->runtime.category = NULL; - const WorkSpace *workspace = CTX_wm_workspace(C); ScrArea *sa = CTX_wm_area(C); - PanelType *pt; View2D *v2d = &ar->v2d; int x, y, w, em; - bool is_context_new = 0; - int scroll; /* XXX, should use some better check? */ /* For now also has hardcoded check for clip editor until it supports actual toolbar. */ - bool use_category_tabs = ((1 << ar->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) || - (ar->regiontype == RGN_TYPE_TOOLS && sa->spacetype == SPACE_CLIP); + bool use_category_tabs = (category_override == NULL) && + ((((1 << ar->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) || + (ar->regiontype == RGN_TYPE_TOOLS && sa->spacetype == SPACE_CLIP))); /* offset panels for small vertical tab area */ const char *category = NULL; const int category_tabs_width = UI_PANEL_CATEGORY_MARGIN_WIDTH; int margin_x = 0; const bool region_layout_based = ar->flag & RGN_FLAG_DYNAMIC_SIZE; - - BLI_SMALLSTACK_DECLARE(pt_stack, PanelType *); - - if (contextnr != -1) { - is_context_new = UI_view2d_tab_set(v2d, contextnr); - } + const bool is_context_new = (contextnr != -1) ? UI_view2d_tab_set(v2d, contextnr) : false; /* before setting the view */ if (vertical) { @@ -2326,45 +2373,21 @@ void ED_region_panels_layout_ex( v2d->scroll |= (V2D_SCROLL_BOTTOM); v2d->scroll &= ~(V2D_SCROLL_RIGHT); } - - scroll = v2d->scroll; - - /* collect panels to draw */ - for (pt = ar->type->paneltypes.last; pt; pt = pt->prev) { - /* Only draw top level panels. */ - if (pt->parent) { - continue; - } - - /* verify context */ - if (contexts && pt->context[0] && !streq_array_any(pt->context, contexts)) { - continue; - } - - /* If we're tagged, only use compatible. */ - if (pt->owner_id[0] && BKE_workspace_owner_id_check(workspace, pt->owner_id) == false) { - continue; - } - - /* draw panel */ - if (pt->draw && (!pt->poll || pt->poll(C, pt))) { - BLI_SMALLSTACK_PUSH(pt_stack, pt); - } - } + const int scroll = v2d->scroll; /* collect categories */ if (use_category_tabs) { UI_panel_category_clear_all(ar); /* gather unique categories */ - BLI_SMALLSTACK_ITER_BEGIN (pt_stack, pt) { + for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) { + PanelType *pt = pt_link->link; if (pt->category[0]) { if (!UI_panel_category_find(ar, pt->category)) { UI_panel_category_add(ar, pt->category); } } } - BLI_SMALLSTACK_ITER_END; if (!UI_panel_category_is_visible(ar)) { use_category_tabs = false; @@ -2392,7 +2415,8 @@ void ED_region_panels_layout_ex( /* set view2d view matrix - UI_block_begin() stores it */ UI_view2d_view_ortho(v2d); - BLI_SMALLSTACK_ITER_BEGIN (pt_stack, pt) { + for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) { + PanelType *pt = pt_link->link; Panel *panel = UI_panel_find_by_type(&ar->panels, pt); if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) { @@ -2403,7 +2427,6 @@ void ED_region_panels_layout_ex( ed_panel_draw(C, sa, ar, &ar->panels, pt, panel, w, em, vertical); } - BLI_SMALLSTACK_ITER_END; /* align panels and return size */ UI_panels_end(C, ar, &x, &y); @@ -2474,9 +2497,11 @@ void ED_region_panels_layout_ex( ar->runtime.category = category; } } + void ED_region_panels_layout(const bContext *C, ARegion *ar) { - ED_region_panels_layout_ex(C, ar, NULL, -1, true); + bool vertical = true; + ED_region_panels_layout_ex(C, ar, &ar->type->paneltypes, NULL, -1, vertical, NULL); } void ED_region_panels_draw(const bContext *C, ARegion *ar) @@ -2525,7 +2550,7 @@ void ED_region_panels_ex( const bContext *C, ARegion *ar, const char *contexts[], int contextnr, const bool vertical) { /* TODO: remove? */ - ED_region_panels_layout_ex(C, ar, contexts, contextnr, vertical); + ED_region_panels_layout_ex(C, ar, &ar->type->paneltypes, contexts, contextnr, vertical, NULL); ED_region_panels_draw(C, ar); } diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index c60469e092f..6a5df8a3776 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -69,15 +69,10 @@ const char *screen_context_dir[] = { "scene", "view_layer", "visible_objects", - "visible_bases", "selectable_objects", - "selectable_bases", "selected_objects", - "selected_bases", "editable_objects", - "editable_bases", "selected_editable_objects", - "selected_editable_bases", "objects_in_mode", "objects_in_mode_unique_data", "visible_bones", @@ -89,7 +84,6 @@ const char *screen_context_dir[] = { "selected_pose_bones_from_active_object", "active_bone", "active_pose_bone", - "active_base", "active_object", "object", "edit_object", @@ -179,52 +173,6 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } - else if (CTX_data_equals(member, "visible_bases")) { - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (BASE_VISIBLE(v3d, base)) { - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "selectable_bases")) { - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (BASE_SELECTABLE(v3d, base)) { - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "selected_bases")) { - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (BASE_SELECTED(v3d, base)) { - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "selected_editable_bases")) { - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (BASE_SELECTED_EDITABLE(v3d, base)) { - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "editable_bases")) { - /* Visible + Editable, but not necessarily selected */ - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (BASE_EDITABLE(v3d, base)) { - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } else if (CTX_data_equals(member, "objects_in_mode")) { if (obact && (obact->mode != OB_MODE_OBJECT)) { FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->type, obact->mode, ob_iter) { @@ -455,13 +403,6 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult return 1; } } - else if (CTX_data_equals(member, "active_base")) { - if (view_layer->basact) { - CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact); - } - - return 1; - } else if (CTX_data_equals(member, "active_object")) { if (obact) { CTX_data_id_pointer_set(result, &obact->id); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 2ce9d732eb7..3a90532aa56 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -675,6 +675,12 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2]) bool do_draw = false; for (ar = area_iter->regionbase.first; ar; ar = ar->next) { + + /* call old area's deactivate if assigned */ + if (ar == old_ar && area_iter->type->deactivate) { + area_iter->type->deactivate(area_iter); + } + if (ar == old_ar || ar == scr->active_region) { do_draw = true; } @@ -884,9 +890,11 @@ static bScreen *screen_fullscreen_find_associated_normal_screen(const Main *bmai { for (bScreen *screen_iter = bmain->screens.first; screen_iter; screen_iter = screen_iter->id.next) { - ScrArea *sa = screen_iter->areabase.first; - if (sa && sa->full == screen) { - return screen_iter; + if ((screen_iter != screen) && ELEM(screen_iter->state, SCREENMAXIMIZED, SCREENFULL)) { + ScrArea *sa = screen_iter->areabase.first; + if (sa && sa->full == screen) { + return screen_iter; + } } } @@ -905,9 +913,7 @@ bScreen *screen_change_prepare( return NULL; } - if (ELEM(screen_new->state, SCREENMAXIMIZED, SCREENFULL)) { - screen_new = screen_fullscreen_find_associated_normal_screen(bmain, screen_new); - } + screen_new = screen_fullscreen_find_associated_normal_screen(bmain, screen_new); /* check for valid winid */ if (!(screen_new->winid == 0 || screen_new->winid == win->winid)) { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 9f452dd79e0..a94c0e35876 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -342,7 +342,7 @@ bool ED_operator_console_active(bContext *C) static bool ed_object_hidden(Object *ob) { /* if hidden but in edit mode, we still display, can happen with animation */ - return ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)); + return ((ob->restrictflag & OB_RESTRICT_VIEWPORT) && !(ob->mode & OB_MODE_EDIT)); } bool ED_operator_object_active(bContext *C) @@ -631,24 +631,6 @@ static bool screen_active_editable(bContext *C) return 0; } -static ARegion *screen_find_region_type(bContext *C, int type) -{ - ARegion *ar = CTX_wm_region(C); - - /* find the header region - * - try context first, but upon failing, search all regions in area... - */ - if ((ar == NULL) || (ar->regiontype != type)) { - ScrArea *sa = CTX_wm_area(C); - ar = BKE_area_find_region_type(sa, type); - } - else { - ar = NULL; - } - - return ar; -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -2431,7 +2413,7 @@ static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge) /* regions in regions. */ if (scalear->alignment & RGN_SPLIT_PREV) { - const int align = scalear->alignment & RGN_ALIGN_ENUM_MASK; + const int align = RGN_ALIGN_ENUM_FROM_MASK(scalear->alignment); if (ELEM(align, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) { ARegion *ar = scalear->prev; @@ -3582,6 +3564,12 @@ static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } +static bool repeat_last_poll(bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + return ED_operator_screenactive(C) && !BLI_listbase_is_empty(&wm->operators); +} + static void SCREEN_OT_repeat_last(wmOperatorType *ot) { /* identifiers */ @@ -3592,7 +3580,7 @@ static void SCREEN_OT_repeat_last(wmOperatorType *ot) /* api callbacks */ ot->exec = repeat_last_exec; - ot->poll = ED_operator_screenactive; + ot->poll = repeat_last_poll; } /** \} */ @@ -3645,6 +3633,12 @@ static int repeat_history_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static bool repeat_history_poll(bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + return ED_operator_screenactive(C) && !BLI_listbase_is_empty(&wm->operators); +} + static void SCREEN_OT_repeat_history(wmOperatorType *ot) { /* identifiers */ @@ -3656,7 +3650,7 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot) ot->invoke = repeat_history_invoke; ot->exec = repeat_history_exec; - ot->poll = ED_operator_screenactive; + ot->poll = repeat_history_poll; RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000); } @@ -3678,6 +3672,12 @@ static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent * return OPERATOR_CANCELLED; } +static bool redo_last_poll(bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + return ED_operator_screenactive(C) && !BLI_listbase_is_empty(&wm->operators); +} + static void SCREEN_OT_redo_last(wmOperatorType *ot) { /* identifiers */ @@ -3688,7 +3688,7 @@ static void SCREEN_OT_redo_last(wmOperatorType *ot) /* api callbacks */ ot->invoke = redo_last_invoke; - ot->poll = ED_operator_screenactive; + ot->poll = redo_last_poll; } /** \} */ @@ -3955,10 +3955,10 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Header Tools Operator +/** \name Region Context Menu Operator (Header/Footer/Navbar) * \{ */ -static bool header_context_menu_poll(bContext *C) +static bool screen_region_context_menu_poll(bContext *C) { ScrArea *sa = CTX_wm_area(C); return (sa && sa->spacetype != SPACE_STATUSBAR); @@ -4008,89 +4008,17 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN } } -static int header_context_menu_invoke(bContext *C, - wmOperator *UNUSED(op), - const wmEvent *UNUSED(event)) -{ - uiPopupMenu *pup; - uiLayout *layout; - - pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE); - layout = UI_popup_menu_layout(pup); - - ED_screens_header_tools_menu_create(C, layout, NULL); - - UI_popup_menu_end(C, pup); - - return OPERATOR_INTERFACE; -} - -static void SCREEN_OT_header_context_menu(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Header Context Menu"; - ot->description = "Display header region context menu"; - ot->idname = "SCREEN_OT_header_context_menu"; - - /* api callbacks */ - ot->poll = header_context_menu_poll; - ot->invoke = header_context_menu_invoke; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Footer Toggle Operator - * \{ */ - -static int footer_exec(bContext *C, wmOperator *UNUSED(op)) -{ - ARegion *ar = screen_find_region_type(C, RGN_TYPE_FOOTER); - - if (ar == NULL) { - return OPERATOR_CANCELLED; - } - - ar->flag ^= RGN_FLAG_HIDDEN; - - ED_area_tag_redraw(CTX_wm_area(C)); - - WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -static void SCREEN_OT_footer(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Toggle Footer"; - ot->description = "Toggle footer display"; - ot->idname = "SCREEN_OT_footer"; - - /* api callbacks */ - ot->exec = footer_exec; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Footer Tools Operator - * \{ */ - -static bool footer_context_menu_poll(bContext *C) -{ - ScrArea *sa = CTX_wm_area(C); - return sa; -} - void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg)) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); const char *but_flip_str = (ar->alignment == RGN_ALIGN_TOP) ? IFACE_("Flip to Bottom") : IFACE_("Flip to Top"); - - uiItemO(layout, IFACE_("Toggle Footer"), ICON_NONE, "SCREEN_OT_footer"); + { + PointerRNA ptr; + RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, sa->spacedata.first, &ptr); + uiItemR(layout, &ptr, "show_region_footer", 0, IFACE_("Show Footer"), ICON_NONE); + } /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); @@ -4107,51 +4035,58 @@ void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UN } } -static int footer_context_menu_invoke(bContext *C, +void ED_screens_navigation_bar_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg)) +{ + const ARegion *ar = CTX_wm_region(C); + const char *but_flip_str = (ar->alignment == RGN_ALIGN_LEFT) ? IFACE_("Flip to Right") : + IFACE_("Flip to Left"); + + /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */ + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + + uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip"); +} + +static int screen_context_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { uiPopupMenu *pup; uiLayout *layout; + const ARegion *ar = CTX_wm_region(C); - pup = UI_popup_menu_begin(C, IFACE_("Footer"), ICON_NONE); - layout = UI_popup_menu_layout(pup); - - ED_screens_footer_tools_menu_create(C, layout, NULL); - - UI_popup_menu_end(C, pup); + if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) { + pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE); + layout = UI_popup_menu_layout(pup); + ED_screens_header_tools_menu_create(C, layout, NULL); + UI_popup_menu_end(C, pup); + } + else if (ar->regiontype == RGN_TYPE_FOOTER) { + pup = UI_popup_menu_begin(C, IFACE_("Footer"), ICON_NONE); + layout = UI_popup_menu_layout(pup); + ED_screens_footer_tools_menu_create(C, layout, NULL); + UI_popup_menu_end(C, pup); + } + else if (ar->regiontype == RGN_TYPE_NAV_BAR) { + pup = UI_popup_menu_begin(C, IFACE_("Navigation Bar"), ICON_NONE); + layout = UI_popup_menu_layout(pup); + ED_screens_navigation_bar_tools_menu_create(C, layout, NULL); + UI_popup_menu_end(C, pup); + } return OPERATOR_INTERFACE; } -static void SCREEN_OT_footer_context_menu(wmOperatorType *ot) +static void SCREEN_OT_region_context_menu(wmOperatorType *ot) { /* identifiers */ - ot->name = "Footer Context Menu"; - ot->description = "Display footer region context menu"; - ot->idname = "SCREEN_OT_footer_context_menu"; + ot->name = "Region Context Menu"; + ot->description = "Display region context menu"; + ot->idname = "SCREEN_OT_region_context_menu"; /* api callbacks */ - ot->poll = footer_context_menu_poll; - ot->invoke = footer_context_menu_invoke; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Navigation Bar Tools Menu - * \{ */ - -void ED_screens_navigation_bar_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg)) -{ - const ARegion *ar = CTX_wm_region(C); - const char *but_flip_str = (ar->alignment == RGN_ALIGN_LEFT) ? IFACE_("Flip to Right") : - IFACE_("Flip to Left"); - - /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */ - uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); - - uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip"); + ot->poll = screen_region_context_menu_poll; + ot->invoke = screen_context_menu_invoke; } /** \} */ @@ -5299,9 +5234,7 @@ void ED_operatortypes_screen(void) WM_operatortype_append(SCREEN_OT_region_scale); WM_operatortype_append(SCREEN_OT_region_flip); WM_operatortype_append(SCREEN_OT_header_toggle_menus); - WM_operatortype_append(SCREEN_OT_header_context_menu); - WM_operatortype_append(SCREEN_OT_footer); - WM_operatortype_append(SCREEN_OT_footer_context_menu); + WM_operatortype_append(SCREEN_OT_region_context_menu); WM_operatortype_append(SCREEN_OT_screen_set); WM_operatortype_append(SCREEN_OT_screen_full_area); WM_operatortype_append(SCREEN_OT_back_to_previous); diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index 6294a64af0f..863e3a15120 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -165,7 +165,9 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager } screen_new = screen_change_prepare(screen_old, screen_new, bmain, C, win); - BLI_assert(BKE_workspace_layout_screen_get(layout_new) == screen_new); + if (BKE_workspace_layout_screen_get(layout_new) != screen_new) { + layout_new = BKE_workspace_layout_find(workspace_new, screen_new); + } if (screen_new == NULL) { return false; @@ -371,13 +373,15 @@ static int workspace_append_activate_exec(bContext *C, wmOperator *op) &bmain->workspaces, idname, offsetof(ID, name) + 2); BLI_assert(appended_workspace != NULL); - /* Reorder to last position. */ - BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true); + if (appended_workspace) { + /* Reorder to last position. */ + BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true); - /* Changing workspace changes context. Do delayed! */ - WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace); + /* Changing workspace changes context. Do delayed! */ + WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; + } } return OPERATOR_CANCELLED; diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 5a45f4946f2..f7a589350f9 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -47,6 +47,7 @@ #include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_brush.h" +#include "BKE_image.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" @@ -154,7 +155,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int } } - ibuf->userflags |= IB_BITMAPDIRTY; + BKE_image_mark_dirty(ima, ibuf); if (tmpibuf) { IMB_freeImBuf(tmpibuf); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 0737218eea4..303c3fac363 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -1837,7 +1837,7 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty) false); } - pjIma->ibuf->userflags |= IB_BITMAPDIRTY; + BKE_image_mark_dirty(pjIma->ima, pjIma->ibuf); /* tile ready, publish */ if (tinf->lock) { BLI_spin_lock(tinf->lock); @@ -1895,7 +1895,7 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps, /* other thread may be initializing the tile so wait here */ while (projima->undoRect[tile_index] == TILE_PENDING) { - ; + /* pass */ } BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y))); @@ -6188,7 +6188,6 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) w, h, IB_rect, - V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL, @@ -6394,7 +6393,7 @@ static const EnumPropertyItem layer_type_items[] = { {0, NULL, 0, NULL, NULL}, }; -static Image *proj_paint_image_create(wmOperator *op, Main *bmain) +static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data) { Image *ima; float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; @@ -6417,6 +6416,11 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain) ima = BKE_image_add_generated( bmain, width, height, imagename, alpha ? 32 : 24, use_float, gen_type, color, false); + if (is_data) { + STRNCPY(ima->colorspace_settings.name, + IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DATA)); + } + return ima; } @@ -6487,6 +6491,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) if (ma) { Main *bmain = CTX_data_main(C); int type = RNA_enum_get(op->ptr, "type"); + bool is_data = (type > LAYER_BASE_COLOR); bNode *imanode; bNodeTree *ntree = ma->nodetree; @@ -6501,7 +6506,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) /* try to add an image node */ imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE); - ima = proj_paint_image_create(op, bmain); + ima = proj_paint_image_create(op, bmain, is_data); imanode->id = &ima->id; nodeSetActive(ntree, imanode); @@ -6553,12 +6558,6 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) } } - if (type > LAYER_BASE_COLOR) { - /* This is a "non color data" image */ - NodeTexImage *tex = imanode->storage; - tex->color_space = SHD_COLORSPACE_NONE; - } - /* Check if the socket in already connected to something */ bNodeLink *link = in_sock ? in_sock->link : NULL; if (in_sock != NULL && link == NULL) { diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c index b80144ac4af..bb73d424152 100644 --- a/source/blender/editors/sculpt_paint/paint_image_undo.c +++ b/source/blender/editors/sculpt_paint/paint_image_undo.c @@ -349,7 +349,9 @@ static void image_undo_restore_list(ListBase *lb, struct UndoIDPtrMap *id_map) undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY); + BKE_image_mark_dirty(ima, ibuf); GPU_free_image(ima); /* force OpenGL reload */ + if (ibuf->rect_float) { ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ } diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 6d003820723..c8ad1b5781d 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -71,6 +71,7 @@ #include "BLI_sys_types.h" #include "ED_mesh.h" /* for face mask functions */ +#include "ED_select_buffer_utils.h" #include "WM_api.h" #include "WM_types.h" @@ -389,7 +390,8 @@ static int imapaint_pick_face(ViewContext *vc, } /* sample only on the exact position */ - *r_index = ED_view3d_select_id_sample(vc, mval[0], mval[1]); + ED_view3d_select_id_validate(vc); + *r_index = ED_select_buffer_sample_point(mval); if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) { return 0; diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c index c1c2964156f..b6a6c897606 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -161,7 +161,7 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot) ot->poll = weight_from_bones_poll; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; /* properties */ ot->prop = RNA_def_enum( @@ -695,7 +695,7 @@ static void gradientVertInit__mapFunc(void *userData, static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event) { wmGesture *gesture = op->customdata; - WPGradient_vertStoreBase *vert_cache = gesture->userdata; + WPGradient_vertStoreBase *vert_cache = gesture->user_data.data; int ret = WM_gesture_straightline_modal(C, op, event); if (ret & OPERATOR_RUNNING_MODAL) { @@ -751,15 +751,15 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) WPGradient_userData data = {NULL}; if (is_interactive) { - if (gesture->userdata == NULL) { - gesture->userdata = MEM_mallocN(sizeof(WPGradient_vertStoreBase) + - (sizeof(WPGradient_vertStore) * me->totvert), - __func__); - gesture->userdata_free = false; + if (gesture->user_data.data == NULL) { + gesture->user_data.data = MEM_mallocN(sizeof(WPGradient_vertStoreBase) + + (sizeof(WPGradient_vertStore) * me->totvert), + __func__); + gesture->user_data.use_free = false; data.is_init = true; wpaint_prev_create( - &((WPGradient_vertStoreBase *)gesture->userdata)->wpp, me->dvert, me->totvert); + &((WPGradient_vertStoreBase *)gesture->user_data.data)->wpp, me->dvert, me->totvert); /* on init only, convert face -> vert sel */ if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { @@ -767,7 +767,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) } } - vert_cache = gesture->userdata; + vert_cache = gesture->user_data.data; } else { if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) { @@ -880,7 +880,7 @@ void PAINT_OT_weight_gradient(wmOperatorType *ot) ot->cancel = WM_gesture_straightline_cancel; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index 3356edd6b36..36cc3605273 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -600,7 +600,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm if (do_island_optimization && (element->island != island_index)) { /* skip this uv if not on the active island */ for (; element->next && !(element->next->separate); element = element->next) { - ; + /* pass */ } continue; } diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 25c05e2d1d0..381173999c4 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -136,7 +136,7 @@ static int sound_open_exec(bContext *C, wmOperator *op) id_us_min(&sound->id); RNA_id_pointer_create(&sound->id, &idptr); - RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); + RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); RNA_property_update(C, &pprop->ptr, pprop->prop); } diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index db504272d2f..bc7f8a0f79d 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -155,7 +155,7 @@ static void actedit_change_action(bContext *C, bAction *act) RNA_id_pointer_create((ID *)act, &idptr); /* set the new pointer, and force a refresh */ - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } @@ -261,7 +261,7 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op)) * 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); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } @@ -619,7 +619,7 @@ void ED_animedit_unlink_action( prop = RNA_struct_find_property(&ptr, "action"); /* clear... */ - RNA_property_pointer_set(&ptr, prop, PointerRNA_NULL); + RNA_property_pointer_set(&ptr, prop, PointerRNA_NULL, NULL); RNA_property_update(C, &ptr, prop); } } diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 9827967f947..f32207fe08b 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -71,68 +71,50 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) int filter; View2D *v2d = &ar->v2d; - float y = 0.0f; size_t items; - int height; /* build list of channels to draw */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); - if (height > BLI_rcti_size_y(&v2d->mask)) { - /* don't use totrect set, as the width stays the same - * (NOTE: this is ok here, the configuration is pretty straightforward) - */ - v2d->tot.ymin = (float)(-height); - } + int height = ACHANNEL_TOT_HEIGHT(ac, items); + v2d->tot.ymin = -height; + /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */ UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY); /* loop through channels, and set up drawing depending on their type */ { /* first pass: just the standard GL-drawing for backdrop + text */ size_t channel_index = 0; + float ymax = ACHANNEL_FIRST_TOP(ac); - y = (float)ACHANNEL_FIRST(ac); - - for (ale = anim_data.first; ale; ale = ale->next) { - float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac), channel_index++) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ - ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index); + ANIM_channel_draw(ac, ale, ymin, ymax, channel_index); } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); - channel_index++; } } { /* second pass: widgets */ uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); size_t channel_index = 0; + float ymax = ACHANNEL_FIRST_TOP(ac); - y = (float)ACHANNEL_FIRST(ac); - - for (ale = anim_data.first; ale; ale = ale->next) { - float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac), channel_index++) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ rctf channel_rect; - BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, yminc, ymaxc); + BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, ymin, ymax); ANIM_channel_draw_widgets(C, ac, ale, block, &channel_rect, channel_index); } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); - channel_index++; } UI_block_end(C, block); @@ -159,8 +141,6 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) bDopeSheet *ads = &saction->ads; AnimData *adt = NULL; - float y; - unsigned char col1[4], col2[4]; unsigned char col1a[4], col2a[4]; unsigned char col1b[4], col2b[4]; @@ -181,14 +161,8 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - int height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); - /* don't use totrect set, as the width stays the same - * (NOTE: this is ok here, the configuration is pretty straightforward) - */ - v2d->tot.ymin = (float)(-height); - - /* first backdrop strips */ - y = (float)(-ACHANNEL_HEIGHT(ac)); + int height = ACHANNEL_TOT_HEIGHT(ac, items); + v2d->tot.ymin = -height; GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); @@ -197,13 +171,15 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) GPU_blend(true); - for (ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + /* first backdrop strips */ + float ymax = ACHANNEL_FIRST_TOP(ac); + + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac)) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); int sel = 0; @@ -264,11 +240,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) } /* draw region twice: firstly backdrop, then the current range */ - immRectf(pos, - v2d->cur.xmin, - (float)y - ACHANNEL_HEIGHT_HALF(ac), - v2d->cur.xmax + EXTRA_SCROLL_PAD, - (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax); } else if (ac->datatype == ANIMCONT_GPENCIL) { unsigned char *color; @@ -285,44 +257,25 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) } /* frames less than one get less saturated background */ immUniformColor4ubv(color); - immRectf(pos, - 0.0f, - (float)y - ACHANNEL_HEIGHT_HALF(ac), - v2d->cur.xmin, - (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, 0.0f, ymin, v2d->cur.xmin, ymax); /* frames one and higher get a saturated background */ immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2)); - immRectf(pos, - v2d->cur.xmin, - (float)y - ACHANNEL_HEIGHT_HALF(ac), - v2d->cur.xmax + EXTRA_SCROLL_PAD, - (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax); } else if (ac->datatype == ANIMCONT_MASK) { /* TODO --- this is a copy of gpencil */ /* frames less than one get less saturated background */ unsigned char *color = sel ? col1 : col2; immUniformColor4ubv(color); - immRectf(pos, - 0.0f, - (float)y - ACHANNEL_HEIGHT_HALF(ac), - v2d->cur.xmin, - (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, 0.0f, ymin, v2d->cur.xmin, ymax); /* frames one and higher get a saturated background */ immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2)); - immRectf(pos, - v2d->cur.xmin, - (float)y - ACHANNEL_HEIGHT_HALF(ac), - v2d->cur.xmax + EXTRA_SCROLL_PAD, - (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax); } } } - - /* Increment the step */ - y -= ACHANNEL_STEP(ac); } GPU_blend(false); @@ -342,21 +295,21 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) * This is to try to optimize this for heavier data sets * 2) Keyframes which are out of view horizontally are disregarded */ - y = (float)(-ACHANNEL_HEIGHT(ac)); - int action_flag = saction->flag; if (saction->mode == SACTCONT_TIMELINE) { action_flag &= ~(SACTION_SHOW_INTERPOLATION | SACTION_SHOW_EXTREMES); } - for (ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + ymax = ACHANNEL_FIRST_TOP(ac); + + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac)) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); + float ycenter = (ymin + ymax) / 2.0f; /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* check if anything to show for this channel */ if (ale->datatype != ALE_NONE) { adt = ANIM_nla_mapping_get(ac, ale); @@ -364,34 +317,32 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) /* draw 'keyframes' for each specific datatype */ switch (ale->datatype) { case ALE_ALL: - draw_summary_channel(v2d, ale->data, y, ac->yscale_fac, action_flag); + draw_summary_channel(v2d, ale->data, ycenter, ac->yscale_fac, action_flag); break; case ALE_SCE: - draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, action_flag); + draw_scene_channel(v2d, ads, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_OB: - draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, action_flag); + draw_object_channel(v2d, ads, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_ACT: - draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, action_flag); + draw_action_channel(v2d, adt, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_GROUP: - draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac, action_flag); + draw_agroup_channel(v2d, adt, ale->data, ycenter, ac->yscale_fac, action_flag); break; case ALE_FCURVE: - draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, action_flag); + draw_fcurve_channel(v2d, adt, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_GPFRAME: - draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac, action_flag); + draw_gpl_channel(v2d, ads, ale->data, ycenter, ac->yscale_fac, action_flag); break; case ALE_MASKLAY: - draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac, action_flag); + draw_masklay_channel(v2d, ads, ale->data, ycenter, ac->yscale_fac, action_flag); break; } } } - - y -= ACHANNEL_STEP(ac); } /* free temporary channels used for drawing */ @@ -460,7 +411,7 @@ void timeline_draw_cache(SpaceAction *saction, Object *ob, Scene *scene) } GPU_matrix_push(); - GPU_matrix_translate_2f(0.0, (float)V2D_SCROLL_HEIGHT_TEXT + yoffs); + GPU_matrix_translate_2f(0.0, (float)V2D_SCROLL_HEIGHT_HANDLES + yoffs); GPU_matrix_scale_2f(1.0, cache_draw_height); switch (pid->type) { diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 8df773e98d6..7fc84db3f75 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -325,24 +325,23 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, /* NOTE: not bool, since we want prioritise individual channels over expanders */ short found = 0; - float y; /* get all items - we need to do it this way */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop through all channels, finding the first one that's selected */ - y = (float)ACHANNEL_FIRST(ac); + float ymax = ACHANNEL_FIRST_TOP(ac); - for (ale = anim_data.first; ale; ale = ale->next) { + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac)) { const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); /* must be selected... */ if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) && ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT)) { /* update best estimate */ - *min = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - *max = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + *min = ymax - ACHANNEL_HEIGHT(ac); + *max = ymax; /* is this high enough priority yet? */ found = acf->channel_role; @@ -354,9 +353,6 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, break; } } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); } /* free all temp data */ @@ -983,8 +979,7 @@ static bool delete_action_keys(bAnimContext *ac) changed = delete_fcurve_keys(fcu); /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && - (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) { + if (BKE_fcurve_is_empty(fcu)) { ANIM_fcurve_delete_from_animdata(ac, adt, fcu); ale->key_data = NULL; } diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 1614e1c432d..1371305487e 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -47,6 +47,7 @@ #include "BKE_gpencil.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "ED_anim_api.h" #include "ED_gpencil.h" @@ -230,7 +231,6 @@ static void box_select_action(bAnimContext *ac, const rcti rect, short mode, sho KeyframeEditFunc ok_cb, select_cb; View2D *v2d = &ac->ar->v2d; rctf rectf; - float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac)); /* Convert mouse coordinates to frame ranges and channel * coordinates corrected for view pan/zoom. */ @@ -254,12 +254,14 @@ static void box_select_action(bAnimContext *ac, const rcti rect, short mode, sho /* init editing data */ memset(&ked, 0, sizeof(KeyframeEditData)); + float ymax = ACHANNEL_FIRST_TOP(ac); + /* loop over data, doing box select */ - for (ale = anim_data.first; ale; ale = ale->next) { + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac)) { AnimData *adt = ANIM_nla_mapping_get(ac, ale); /* get new vertical minimum extent of channel */ - ymin = ymax - ACHANNEL_STEP(ac); + float ymin = ymax - ACHANNEL_STEP(ac); /* set horizontal range (if applicable) */ if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) { @@ -314,9 +316,6 @@ static void box_select_action(bAnimContext *ac, const rcti rect, short mode, sho } } } - - /* set minimum extent to be the maximum of the next channel */ - ymax = ymin; } /* cleanup */ @@ -418,7 +417,6 @@ static void region_select_action_keys( KeyframeEditFunc ok_cb, select_cb; View2D *v2d = &ac->ar->v2d; rctf rectf, scaled_rectf; - float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac)); /* Convert mouse coordinates to frame ranges and channel * coordinates corrected for view pan/zoom. */ @@ -448,15 +446,17 @@ static void region_select_action_keys( ked.data = &scaled_rectf; } + float ymax = ACHANNEL_FIRST_TOP(ac); + /* loop over data, doing region select */ - for (ale = anim_data.first; ale; ale = ale->next) { + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac)) { AnimData *adt = ANIM_nla_mapping_get(ac, ale); /* get new vertical minimum extent of channel */ - ymin = ymax - ACHANNEL_STEP(ac); + float ymin = ymax - ACHANNEL_STEP(ac); /* compute midpoint of channel (used for testing if the key is in the region or not) */ - ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF(ac); + ked.channel_y = (ymin + ymax) / 2.0f; /* if channel is mapped in NLA, apply correction * - Apply to the bounds being checked, not all the keyframe points, @@ -520,9 +520,6 @@ static void region_select_action_keys( break; } } - - /* set minimum extent to be the maximum of the next channel */ - ymax = ymin; } /* cleanup */ @@ -1453,7 +1450,7 @@ static void mouse_action_keys(bAnimContext *ac, /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); UI_view2d_listview_view_to_cell( - v2d, 0, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index); + 0, ACHANNEL_STEP(ac), 0, ACHANNEL_FIRST_TOP(ac), x, y, NULL, &channel_index); /* x-range to check is +/- 7px for standard keyframe under standard dpi/y-scale * (in screen/region-space), on either side of mouse click (size of keyframe icon). diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 843abbd16db..972f19bb643 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -45,6 +45,7 @@ #include "WM_types.h" #include "WM_message.h" +#include "UI_interface.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -52,6 +53,7 @@ #include "ED_screen.h" #include "ED_anim_api.h" #include "ED_markers.h" +#include "ED_time_scrub_ui.h" #include "action_intern.h" /* own include */ #include "GPU_framebuffer.h" @@ -69,7 +71,7 @@ static SpaceLink *action_new(const ScrArea *sa, const Scene *scene) saction->autosnap = SACTSNAP_FRAME; saction->mode = SACTCONT_DOPESHEET; saction->mode_prev = SACTCONT_DOPESHEET; - saction->flag = SACTION_SHOW_INTERPOLATION; + saction->flag = SACTION_SHOW_INTERPOLATION | SACTION_SHOW_MARKER_LINES; saction->ads.filterflag |= ADS_FILTER_SUMMARY; @@ -125,7 +127,7 @@ static SpaceLink *action_new(const ScrArea *sa, const Scene *scene) ar->v2d.minzoom = 0.01f; ar->v2d.maxzoom = 50; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); ar->v2d.scroll |= (V2D_SCROLL_RIGHT); ar->v2d.keepzoom = V2D_LOCKZOOM_Y; ar->v2d.keepofs = V2D_KEEPOFS_Y; @@ -234,20 +236,13 @@ static void action_main_region_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + /* scrubbing region */ + ED_scrubbing_draw(ar, scene, saction->flag & SACTION_DRAWTIME, true); + /* scrollers */ scrollers = UI_view2d_scrollers_calc(v2d, NULL); UI_view2d_scrollers_draw(v2d, scrollers); UI_view2d_scrollers_free(scrollers); - - /* frame numbers */ - UI_view2d_draw_scale_x__discrete_frames_or_seconds( - ar, v2d, &v2d->hor, scene, saction->flag & SACTION_DRAWTIME); - - /* draw current frame number-indicator on top of scrollers */ - if ((saction->flag & SACTION_NODRAWCFRANUM) == 0) { - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); - } } /* add handlers, stuff you only do once or on area/region changes */ @@ -285,6 +280,9 @@ static void action_channel_region_draw(const bContext *C, ARegion *ar) draw_channel_names((bContext *)C, &ac, ar); } + /* channel filter next to scrubbing area */ + ED_channel_search_draw(C, ar, ac.ads); + /* reset view matrix */ UI_view2d_view_restore(C); @@ -869,7 +867,7 @@ void ED_spacetype_action(void) art->draw = action_main_region_draw; art->listener = action_main_region_listener; art->message_subscribe = saction_main_region_message_subscribe; - art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; + art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; BLI_addhead(&st->regiontypes, art); @@ -901,7 +899,7 @@ void ED_spacetype_action(void) /* regions: UI buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 200; + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI; art->listener = action_region_listener; art->init = action_buttons_area_init; diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 607c3ddbb10..fde8b8f85f8 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -785,6 +785,10 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r SpaceProperties *sbuts = CTX_wm_space_properties(C); ButsContextPath *path = sbuts ? sbuts->path : NULL; + if (sbuts->mainb == BCONTEXT_TOOL) { + return 0; + } + if (!path) { return 0; } diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index fe4ed0209bf..500efe4bb4d 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -56,15 +56,10 @@ static int context_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { - const ARegion *ar = CTX_wm_region(C); uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Context Menu"), ICON_NONE); uiLayout *layout = UI_popup_menu_layout(pup); uiItemM(layout, "INFO_MT_area", NULL, ICON_NONE); - if (ar->regiontype == RGN_TYPE_NAV_BAR) { - ED_screens_navigation_bar_tools_menu_create(C, layout, NULL); - } - UI_popup_menu_end(C, pup); return OPERATOR_INTERFACE; diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index f9244049d54..9b0150d731d 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -34,6 +34,7 @@ #include "ED_space_api.h" #include "ED_screen.h" +#include "ED_view3d.h" /* To draw toolbar UI. */ #include "WM_api.h" #include "WM_types.h" @@ -198,105 +199,7 @@ static void buttons_main_region_layout_properties(const bContext *C, } const bool vertical = true; - ED_region_panels_layout_ex(C, ar, contexts, sbuts->mainb, vertical); -} - -static void buttons_main_region_layout_tool(const bContext *C, ARegion *ar) -{ - const enum eContextObjectMode mode = CTX_data_mode_enum(C); - - const char *contexts_base[5] = {NULL}; - contexts_base[0] = ".active_tool"; - const char **contexts = &contexts_base[1]; - - /* Hard coded to 3D view. */ - { - switch (mode) { - case CTX_MODE_EDIT_MESH: - ARRAY_SET_ITEMS(contexts, ".mesh_edit"); - break; - case CTX_MODE_EDIT_CURVE: - ARRAY_SET_ITEMS(contexts, ".curve_edit"); - break; - case CTX_MODE_EDIT_SURFACE: - ARRAY_SET_ITEMS(contexts, ".curve_edit"); - break; - case CTX_MODE_EDIT_TEXT: - ARRAY_SET_ITEMS(contexts, ".text_edit"); - break; - case CTX_MODE_EDIT_ARMATURE: - ARRAY_SET_ITEMS(contexts, ".armature_edit"); - break; - case CTX_MODE_EDIT_METABALL: - ARRAY_SET_ITEMS(contexts, ".mball_edit"); - break; - case CTX_MODE_EDIT_LATTICE: - ARRAY_SET_ITEMS(contexts, ".lattice_edit"); - break; - case CTX_MODE_POSE: - ARRAY_SET_ITEMS(contexts, ".posemode"); - break; - case CTX_MODE_SCULPT: - ARRAY_SET_ITEMS(contexts, ".paint_common", ".sculpt_mode"); - break; - case CTX_MODE_PAINT_WEIGHT: - ARRAY_SET_ITEMS(contexts, ".paint_common", ".weightpaint"); - break; - case CTX_MODE_PAINT_VERTEX: - ARRAY_SET_ITEMS(contexts, ".paint_common", ".vertexpaint"); - break; - case CTX_MODE_PAINT_TEXTURE: - ARRAY_SET_ITEMS(contexts, ".paint_common", ".imagepaint"); - break; - case CTX_MODE_PARTICLE: - ARRAY_SET_ITEMS(contexts, ".paint_common", ".particlemode"); - break; - case CTX_MODE_OBJECT: - ARRAY_SET_ITEMS(contexts, ".objectmode"); - break; - case CTX_MODE_PAINT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_paint"); - break; - case CTX_MODE_SCULPT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt"); - break; - case CTX_MODE_WEIGHT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_weight"); - break; - default: - break; - } - } - - /* for grease pencil we don't use tool system yet, so we need check outside - * workspace->tools_space_type because this value is not available - */ - switch (mode) { - case CTX_MODE_PAINT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_paint"); - break; - case CTX_MODE_SCULPT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt"); - break; - case CTX_MODE_WEIGHT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_weight"); - break; - case CTX_MODE_EDIT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_edit"); - break; - default: - break; - } - - int i = 0; - while (contexts_base[i]) { - i++; - } - BLI_assert(i < ARRAY_SIZE(contexts_base)); - contexts_base[i] = ".workspace"; - - const bool vertical = true; - ED_region_panels_layout_ex(C, ar, contexts_base, -1, vertical); + ED_region_panels_layout_ex(C, ar, &ar->type->paneltypes, contexts, sbuts->mainb, vertical, NULL); } static void buttons_main_region_layout(const bContext *C, ARegion *ar) @@ -305,7 +208,7 @@ static void buttons_main_region_layout(const bContext *C, ARegion *ar) SpaceProperties *sbuts = CTX_wm_space_properties(C); if (sbuts->mainb == BCONTEXT_TOOL) { - buttons_main_region_layout_tool(C, ar); + ED_view3d_buttons_region_layout_ex(C, ar, "Tool"); } else { buttons_main_region_layout_properties(C, sbuts, ar); @@ -400,9 +303,6 @@ static void buttons_header_region_message_subscribe(const bContext *UNUSED(C), static void buttons_navigation_bar_region_init(wmWindowManager *wm, ARegion *ar) { - wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Property Editor", SPACE_PROPERTIES, 0); - WM_event_add_keymap_handler(&ar->handlers, keymap); - ar->flag |= RGN_FLAG_PREFSIZE_OR_HIDDEN; ED_region_panels_init(wm, ar); @@ -749,7 +649,7 @@ void ED_spacetype_buttons(void) art->regionid = RGN_TYPE_NAV_BAR; art->prefsizex = AREAMINX - 3; /* XXX Works and looks best, * should we update AREAMINX accordingly? */ - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES | ED_KEYMAP_NAVBAR; art->init = buttons_navigation_bar_region_init; art->draw = buttons_navigation_bar_region_draw; art->message_subscribe = buttons_navigation_bar_region_message_subscribe; diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index c985d61a8b8..2496b16ffae 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -808,12 +808,13 @@ void uiTemplateMovieclipInformation(uiLayout *layout, user = userptr->data; col = uiLayoutColumn(layout, false); + uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_RIGHT); ibuf = BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, MOVIECLIP_CACHE_SKIP); /* Display frame dimensions, channels number and byffer type. */ BKE_movieclip_get_size(clip, user, &width, &height); - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Size %d x %d"), width, height); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("%d x %d"), width, height); if (ibuf) { if (ibuf->rect_float) { diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 70dc1caf36f..081515ca4bc 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -35,7 +35,7 @@ struct bContext; struct wmOperatorType; /* channel heights */ -#define CHANNEL_FIRST (-0.8f * U.widget_unit) +#define CHANNEL_FIRST (-UI_SCRUBBING_MARGIN_Y - CHANNEL_HEIGHT_HALF - CHANNEL_SKIP) #define CHANNEL_HEIGHT (0.8f * U.widget_unit) #define CHANNEL_HEIGHT_HALF (0.4f * U.widget_unit) #define CHANNEL_SKIP (0.1f * U.widget_unit) diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 3f971c4444a..710a46fdd51 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -245,7 +245,7 @@ static int open_exec(bContext *C, wmOperator *op) id_us_min(&clip->id); RNA_id_pointer_create(&clip->id, &idptr); - RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); + RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); RNA_property_update(C, &pprop->ptr, pprop->prop); } else if (sc) { @@ -955,10 +955,10 @@ static bool change_frame_poll(bContext *C) { /* prevent changes during render */ if (G.is_rendering) { - return 0; + return false; } - - return ED_space_clip_poll(C); + SpaceClip *space_clip = CTX_wm_space_clip(C); + return space_clip != NULL; } static void change_frame_apply(bContext *C, wmOperator *op) diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 542f99e49ee..f26175a6c57 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -47,6 +47,7 @@ #include "ED_mask.h" #include "ED_space_api.h" #include "ED_screen.h" +#include "ED_time_scrub_ui.h" #include "ED_select_utils.h" #include "ED_clip.h" #include "ED_transform.h" @@ -94,7 +95,7 @@ static void init_preview_region(const Scene *scene, ar->v2d.minzoom = 0.01f; ar->v2d.maxzoom = 50; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); ar->v2d.scroll |= (V2D_SCROLL_RIGHT); ar->v2d.keepzoom = V2D_LOCKZOOM_Y; ar->v2d.keepofs = V2D_KEEPOFS_Y; @@ -115,8 +116,8 @@ static void init_preview_region(const Scene *scene, ar->v2d.max[0] = MAXFRAMEF; ar->v2d.max[1] = FLT_MAX; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); - ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_SCALE_VERTICAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); + ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HANDLES); ar->v2d.minzoom = 0.0f; ar->v2d.maxzoom = 0.0f; @@ -249,7 +250,7 @@ static SpaceLink *clip_new(const ScrArea *sa, const Scene *scene) sc->zoom = 1.0f; sc->path_length = 20; sc->scopes.track_preview_height = 120; - sc->around = V3D_AROUND_LOCAL_ORIGINS; + sc->around = V3D_AROUND_CENTER_MEDIAN; /* header */ ar = MEM_callocN(sizeof(ARegion), "header for clip"); @@ -1001,9 +1002,13 @@ static void clip_preview_region_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ + keymap = WM_keymap_ensure(wm->defaultconf, "Clip", SPACE_CLIP, 0); WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap); + keymap = WM_keymap_ensure(wm->defaultconf, "Clip Scrubbing", SPACE_CLIP, RGN_TYPE_PREVIEW); + WM_event_add_keymap_handler_poll(&ar->handlers, keymap, ED_event_in_scrubbing_region); + keymap = WM_keymap_ensure(wm->defaultconf, "Clip Graph Editor", SPACE_CLIP, 0); WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap); @@ -1041,22 +1046,24 @@ static void graph_region_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + /* time-scrubbing */ + ED_scrubbing_draw(ar, scene, sc->flag & SC_SHOW_SECONDS, true); + /* scrollers */ scrollers = UI_view2d_scrollers_calc(v2d, NULL); UI_view2d_scrollers_draw(v2d, scrollers); UI_view2d_scrollers_free(scrollers); /* scale indicators */ - UI_view2d_draw_scale_x__discrete_frames_or_seconds( - ar, v2d, &v2d->hor, scene, sc->flag & SC_SHOW_SECONDS); - UI_view2d_draw_scale_y__values(ar, v2d, &v2d->vert); - - /* current frame indicator */ - if (sc->flag & SC_SHOW_SECONDS) { - cfra_flag |= DRAWCFRA_UNIT_SECONDS; + { + rcti rect; + BLI_rcti_init(&rect, + 0, + 15 * UI_DPI_FAC, + 15 * UI_DPI_FAC, + UI_DPI_FAC * ar->sizey - UI_SCRUBBING_MARGIN_Y); + UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_TEXT); } - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); } static void dopesheet_region_draw(const bContext *C, ARegion *ar) @@ -1093,18 +1100,13 @@ static void dopesheet_region_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + /* time-scrubbing */ + ED_scrubbing_draw(ar, scene, sc->flag & SC_SHOW_SECONDS, true); + /* scrollers */ scrollers = UI_view2d_scrollers_calc(v2d, NULL); UI_view2d_scrollers_draw(v2d, scrollers); UI_view2d_scrollers_free(scrollers); - - /* frame numbers */ - UI_view2d_draw_scale_x__discrete_frames_or_seconds( - ar, v2d, &v2d->hor, scene, sc->flag & SC_SHOW_SECONDS); - - /* current frame number indicator */ - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); } static void clip_preview_region_draw(const bContext *C, ARegion *ar) @@ -1369,7 +1371,7 @@ void ED_spacetype_clip(void) /* regions: properties */ art = MEM_callocN(sizeof(ARegionType), "spacetype clip region properties"); art->regionid = RGN_TYPE_UI; - art->prefsizex = UI_COMPACT_PANEL_WIDTH; + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI; art->init = clip_properties_region_init; art->draw = clip_properties_region_draw; @@ -1380,7 +1382,7 @@ void ED_spacetype_clip(void) /* regions: tools */ art = MEM_callocN(sizeof(ARegionType), "spacetype clip region tools"); art->regionid = RGN_TYPE_TOOLS; - art->prefsizex = UI_COMPACT_PANEL_WIDTH; + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI; art->listener = clip_props_region_listener; art->init = clip_tools_region_init; diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 18d48b426e0..b51baafbcf5 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -1299,6 +1299,12 @@ void CLIP_OT_hide_tracks_clear(wmOperatorType *ot) /********************** frame jump operator *********************/ +static bool frame_jump_poll(bContext *C) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + return space_clip != NULL; +} + static int frame_jump_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -1377,7 +1383,7 @@ void CLIP_OT_frame_jump(wmOperatorType *ot) /* api callbacks */ ot->exec = frame_jump_exec; - ot->poll = ED_space_clip_poll; + ot->poll = frame_jump_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index bb8680682d2..6b3baa1e766 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -478,7 +478,7 @@ static void file_draw_preview(uiBlock *block, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); if (icon) { - UI_icon_draw_aspect((float)xco, (float)yco, icon, icon_aspect, 1.0f, NULL); + UI_icon_draw_ex((float)xco, (float)yco, icon, icon_aspect, 1.0f, 0.0f, NULL, false); } /* border */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 674735f3e1d..5ac7ff72aed 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1011,7 +1011,7 @@ static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op)) BLI_make_file_string( "/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); fsmenu_write_file(fsmenu, name); - fsmenu_refresh_bookmarks_status(fsmenu); + fsmenu_refresh_bookmarks_status(CTX_wm_manager(C), fsmenu); ED_area_tag_refresh(sa); ED_area_tag_redraw(sa); } @@ -1567,6 +1567,9 @@ static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused)) /* refresh system directory menu */ fsmenu_refresh_system_category(fsmenu); + /* Update bookmarks 'valid' state. */ + fsmenu_refresh_bookmarks_status(wm, fsmenu); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 38423a87447..b50c37baae6 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -44,6 +44,9 @@ # include "BLI_winstuff.h" #endif +#include "WM_api.h" +#include "WM_types.h" + #ifdef __APPLE__ # include <Carbon/Carbon.h> #endif /* __APPLE__ */ @@ -721,31 +724,59 @@ void fsmenu_refresh_system_category(struct FSMenu *fsmenu) fsmenu_read_system(fsmenu, true); } -void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu) +static void fsmenu_free_ex(FSMenu **fsmenu) { - int categories[] = { - FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT}; - int i; - - for (i = sizeof(categories) / sizeof(*categories); i--;) { - FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, categories[i]); - for (; fsm_iter; fsm_iter = fsm_iter->next) { - fsmenu_entry_refresh_valid(fsm_iter); - } + if (*fsmenu != NULL) { + fsmenu_free_category(*fsmenu, FS_CATEGORY_SYSTEM); + fsmenu_free_category(*fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS); + fsmenu_free_category(*fsmenu, FS_CATEGORY_BOOKMARKS); + fsmenu_free_category(*fsmenu, FS_CATEGORY_RECENT); + MEM_freeN(*fsmenu); } + + *fsmenu = NULL; } void fsmenu_free(void) { - if (g_fsmenu) { - fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM); - fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS); - fsmenu_free_category(g_fsmenu, FS_CATEGORY_BOOKMARKS); - fsmenu_free_category(g_fsmenu, FS_CATEGORY_RECENT); - MEM_freeN(g_fsmenu); + fsmenu_free_ex(&g_fsmenu); +} + +static void fsmenu_copy_category(struct FSMenu *fsmenu_dst, + struct FSMenu *fsmenu_src, + const FSMenuCategory category) +{ + FSMenuEntry *fsm_dst_prev = NULL, *fsm_dst_head = NULL; + FSMenuEntry *fsm_src_iter = ED_fsmenu_get_category(fsmenu_src, category); + + for (; fsm_src_iter != NULL; fsm_src_iter = fsm_src_iter->next) { + FSMenuEntry *fsm_dst = MEM_dupallocN(fsm_src_iter); + if (fsm_dst->path != NULL) { + fsm_dst->path = MEM_dupallocN(fsm_dst->path); + } + + if (fsm_dst_prev != NULL) { + fsm_dst_prev->next = fsm_dst; + } + else { + fsm_dst_head = fsm_dst; + } + fsm_dst_prev = fsm_dst; } - g_fsmenu = NULL; + ED_fsmenu_set_category(fsmenu_dst, category, fsm_dst_head); +} + +static FSMenu *fsmenu_copy(FSMenu *fsmenu) +{ + FSMenu *fsmenu_copy = MEM_dupallocN(fsmenu); + + fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_SYSTEM); + fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_SYSTEM_BOOKMARKS); + fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_BOOKMARKS); + fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_RECENT); + + return fsmenu_copy; } int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *dir) @@ -761,3 +792,99 @@ int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory categor return -1; } + +/* Thanks to some bookmarks sometimes being network drives that can have tens of seconds of delay + * before being defined as unreachable by the OS, we need to validate the bookmarks in an async + * job... + */ +static void fsmenu_bookmark_validate_job_startjob(void *fsmenuv, + short *stop, + short *do_update, + float *UNUSED(progress)) +{ + FSMenu *fsmenu = fsmenuv; + + int categories[] = { + FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT}; + + for (size_t i = ARRAY_SIZE(categories); i--;) { + FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, categories[i]); + for (; fsm_iter; fsm_iter = fsm_iter->next) { + if (*stop) { + return; + } + /* Note that we do not really need atomics primitives or thread locks here, since this only + * sets one short, which is assumed to be 'atomic'-enough for us here. */ + fsmenu_entry_refresh_valid(fsm_iter); + *do_update = true; + } + } +} + +static void fsmenu_bookmark_validate_job_update(void *fsmenuv) +{ + FSMenu *fsmenu_job = fsmenuv; + + int categories[] = { + FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT}; + + for (size_t i = ARRAY_SIZE(categories); i--;) { + FSMenuEntry *fsm_iter_src = ED_fsmenu_get_category(fsmenu_job, categories[i]); + FSMenuEntry *fsm_iter_dst = ED_fsmenu_get_category(ED_fsmenu_get(), categories[i]); + for (; fsm_iter_dst != NULL; fsm_iter_dst = fsm_iter_dst->next) { + while (fsm_iter_src != NULL && !STREQ(fsm_iter_dst->path, fsm_iter_src->path)) { + fsm_iter_src = fsm_iter_src->next; + } + if (fsm_iter_src == NULL) { + return; + } + fsm_iter_dst->valid = fsm_iter_src->valid; + } + } +} + +static void fsmenu_bookmark_validate_job_end(void *fsmenuv) +{ + /* In case there would be some dangling update... */ + fsmenu_bookmark_validate_job_update(fsmenuv); +} + +static void fsmenu_bookmark_validate_job_free(void *fsmenuv) +{ + FSMenu *fsmenu = fsmenuv; + fsmenu_free_ex(&fsmenu); +} + +static void fsmenu_bookmark_validate_job_start(wmWindowManager *wm) +{ + wmJob *wm_job; + FSMenu *fsmenu_job = fsmenu_copy(g_fsmenu); + + /* setup job */ + wm_job = WM_jobs_get( + wm, wm->winactive, wm, "Validating Bookmarks...", 0, WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE); + WM_jobs_customdata_set(wm_job, fsmenu_job, fsmenu_bookmark_validate_job_free); + WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST); + WM_jobs_callbacks(wm_job, + fsmenu_bookmark_validate_job_startjob, + NULL, + fsmenu_bookmark_validate_job_update, + fsmenu_bookmark_validate_job_end); + + /* start the job */ + WM_jobs_start(wm, wm_job); +} + +static void fsmenu_bookmark_validate_job_stop(wmWindowManager *wm) +{ + WM_jobs_kill_type(wm, wm, WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE); +} + +void fsmenu_refresh_bookmarks_status(wmWindowManager *wm, FSMenu *fsmenu) +{ + BLI_assert(fsmenu == ED_fsmenu_get()); + UNUSED_VARS_NDEBUG(fsmenu); + + fsmenu_bookmark_validate_job_stop(wm); + fsmenu_bookmark_validate_job_start(wm); +} diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h index cb0dccf0499..d9850cb855d 100644 --- a/source/blender/editors/space_file/fsmenu.h +++ b/source/blender/editors/space_file/fsmenu.h @@ -68,7 +68,7 @@ void fsmenu_free(void); void fsmenu_refresh_system_category(struct FSMenu *fsmenu); /** Refresh 'valid' status of all menu entries */ -void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu); +void fsmenu_refresh_bookmarks_status(struct wmWindowManager *wm, struct FSMenu *fsmenu); /** Get active index based on given directory. */ int fsmenu_get_active_indices(struct FSMenu *fsmenu, diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 9fb07042104..1fd878e4662 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -142,18 +142,16 @@ static void file_free(SpaceLink *sl) } /* spacetype; init callback, area size changes, screen set, etc */ -static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa) +static void file_init(wmWindowManager *wm, ScrArea *sa) { SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; + struct FSMenu *fsmenu = ED_fsmenu_get(); /* refresh system directory list */ - fsmenu_refresh_system_category(ED_fsmenu_get()); + fsmenu_refresh_system_category(fsmenu); - /* Update bookmarks 'valid' state. - * Done here, because it seems BLI_is_dir() can have huge impact on performances - * in some cases, on win systems... See T43684. - */ - fsmenu_refresh_bookmarks_status(ED_fsmenu_get()); + /* Update bookmarks 'valid' state. */ + fsmenu_refresh_bookmarks_status(wm, fsmenu); if (sfile->layout) { sfile->layout->dirty = true; diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index dfc59a79c49..062c9f86fab 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -1230,9 +1230,8 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) int filter; View2D *v2d = &ar->v2d; - float y = 0.0f, height; + float height; size_t items; - int i = 0; /* build list of channels to draw */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); @@ -1240,62 +1239,47 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) /* Update max-extent of channels here (taking into account scrollers): * - this is done to allow the channel list to be scrollable, but must be done here - * to avoid regenerating the list again and/or also because channels list is drawn first - * - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for - * start of list offset, and the second is as a correction for the scrollers. - */ - height = (float)((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac) * 2)); - UI_view2d_totRect_set(v2d, BLI_rcti_size_x(&ar->v2d.mask), height); + * to avoid regenerating the list again and/or also because channels list is drawn first */ + height = ACHANNEL_TOT_HEIGHT(ac, items); + v2d->tot.ymin = -height; /* loop through channels, and set up drawing depending on their type */ { /* first pass: just the standard GL-drawing for backdrop + text */ size_t channel_index = 0; + float ymax = ACHANNEL_FIRST_TOP(ac); - y = (float)ACHANNEL_FIRST(ac); - - for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac), channel_index++) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ - ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index); + ANIM_channel_draw(ac, ale, ymin, ymax, channel_index); } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); - channel_index++; } } { /* second pass: widgets */ uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); size_t channel_index = 0; - - y = (float)ACHANNEL_FIRST(ac); + float ymax = ACHANNEL_FIRST_TOP(ac); /* set blending again, as may not be set in previous step */ GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); GPU_blend(true); - for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac), channel_index++) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ rctf channel_rect; - BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax - V2D_SCROLL_WIDTH, yminc, ymaxc); + BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax - V2D_SCROLL_WIDTH, ymin, ymax); ANIM_channel_draw_widgets(C, ac, ale, block, &channel_rect, channel_index); } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); - channel_index++; } UI_block_end(C, block); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 0954538e430..b3fafa09256 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -55,6 +55,7 @@ #include "DEG_depsgraph_build.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "ED_anim_api.h" #include "ED_keyframing.h" @@ -282,10 +283,18 @@ static int graphkeys_viewall(bContext *C, do_sel_only, include_handles); + /* Give some more space at the borders. */ BLI_rctf_scale(&cur_new, 1.1f); - UI_view2d_smooth_view(C, ac.ar, &cur_new, smooth_viewtx); + /* Take regions into account, that could block the view. */ + float pad_top = UI_SCRUBBING_MARGIN_Y; + float pad_bottom = 0; + if (!BLI_listbase_is_empty(ED_context_get_markers(C))) { + pad_bottom = UI_MARKER_MARGIN_Y; + } + BLI_rctf_pad_y(&cur_new, ac.ar->sizey * UI_DPI_FAC, pad_bottom, pad_top); + UI_view2d_smooth_view(C, ac.ar, &cur_new, smooth_viewtx); return OPERATOR_FINISHED; } @@ -1172,9 +1181,7 @@ static bool delete_graph_keys(bAnimContext *ac) } /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && - (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) && - (fcu->driver == NULL)) { + if (BKE_fcurve_is_empty(fcu)) { ANIM_fcurve_delete_from_animdata(ac, adt, fcu); ale->key_data = NULL; } @@ -2820,6 +2827,7 @@ void GRAPH_OT_fmodifier_add(wmOperatorType *ot) /* id-props */ prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", ""); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ACTION); RNA_def_enum_funcs(prop, graph_fmodifier_itemf); ot->prop = prop; diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 13a42f091f6..5ea07c56286 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -1141,7 +1141,7 @@ typedef enum eGraphVertIndex { /* Tolerance for absolute radius (in pixels) of the vert from the cursor to use */ // TODO: perhaps this should depend a bit on the size that the user set the vertices to be? -#define GVERTSEL_TOL 10 +#define GVERTSEL_TOL (10 * U.pixelsize) /* ....... */ diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index 86d0b961a31..4e131c653f8 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -42,6 +42,7 @@ #include "ED_screen.h" #include "ED_anim_api.h" #include "ED_markers.h" +#include "ED_time_scrub_ui.h" #include "GPU_immediate.h" #include "GPU_state.h" @@ -57,6 +58,7 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "graph_intern.h" // own include @@ -79,7 +81,7 @@ static SpaceLink *graph_new(const ScrArea *UNUSED(sa), const Scene *scene) /* settings for making it easier by default to just see what you're interested in tweaking */ sipo->ads->filterflag |= ADS_FILTER_ONLYSEL; - sipo->flag |= SIPO_SELVHANDLESONLY; + sipo->flag |= SIPO_SELVHANDLESONLY | SIPO_MARKER_LINES; /* header */ ar = MEM_callocN(sizeof(ARegion), "header for graphedit"); @@ -124,8 +126,8 @@ static SpaceLink *graph_new(const ScrArea *UNUSED(sa), const Scene *scene) ar->v2d.max[0] = MAXFRAMEF; ar->v2d.max[1] = FLT_MAX; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); - ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_SCALE_VERTICAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); + ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HANDLES); ar->v2d.keeptot = 0; @@ -291,12 +293,14 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar) } /* markers */ - UI_view2d_view_orthoSpecial(ar, v2d, 1); - int marker_draw_flag = DRAW_MARKERS_MARGIN; - if (sipo->flag & SIPO_MARKER_LINES) { - marker_draw_flag |= DRAW_MARKERS_LINES; + if (sipo->mode != SIPO_MODE_DRIVERS) { + UI_view2d_view_orthoSpecial(ar, v2d, 1); + int marker_draw_flag = DRAW_MARKERS_MARGIN; + if (sipo->flag & SIPO_MARKER_LINES) { + marker_draw_flag |= DRAW_MARKERS_LINES; + } + ED_markers_draw(C, marker_draw_flag); } - ED_markers_draw(C, marker_draw_flag); /* preview range */ UI_view2d_view_ortho(v2d); @@ -309,6 +313,9 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + /* time-scrubbing */ + ED_scrubbing_draw(ar, scene, display_seconds, false); + /* scrollers */ // FIXME: args for scrollers depend on the type of data being shown... scrollers = UI_view2d_scrollers_calc(v2d, NULL); @@ -316,13 +323,14 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar) UI_view2d_scrollers_free(scrollers); /* scale numbers */ - UI_view2d_draw_scale_x__frames_or_seconds(ar, v2d, &v2d->hor, scene, display_seconds); - UI_view2d_draw_scale_y__values(ar, v2d, &v2d->vert); - - /* draw current frame number-indicator on top of scrollers */ - if ((sipo->mode != SIPO_MODE_DRIVERS) && ((sipo->flag & SIPO_NODRAWCFRANUM) == 0)) { - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); + { + rcti rect; + BLI_rcti_init(&rect, + 0, + 15 * UI_DPI_FAC, + 15 * UI_DPI_FAC, + UI_DPI_FAC * ar->sizey - UI_SCRUBBING_MARGIN_Y); + UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_SCROLL_TEXT); } } @@ -367,6 +375,9 @@ static void graph_channel_region_draw(const bContext *C, ARegion *ar) graph_draw_channel_names((bContext *)C, &ac, ar); } + /* channel filter next to scrubbing area */ + ED_channel_search_draw(C, ar, ac.ads); + /* reset view matrix */ UI_view2d_view_restore(C); @@ -849,7 +860,7 @@ void ED_spacetype_ipo(void) art->draw = graph_main_region_draw; art->listener = graph_region_listener; art->message_subscribe = graph_region_message_subscribe; - art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; + art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; BLI_addhead(&st->regiontypes, art); @@ -880,7 +891,7 @@ void ED_spacetype_ipo(void) /* regions: UI buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 200; + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = graph_region_listener; art->init = graph_buttons_region_init; diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 752eedebe71..b32f5ef6d9e 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -42,6 +42,7 @@ #include "RE_pipeline.h" +#include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -62,81 +63,6 @@ #define B_NOP -1 #define MAX_IMAGE_INFO_LEN 128 -/* proto */ - -static void image_info( - Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf, char *str, size_t len) -{ - size_t ofs = 0; - - str[0] = 0; - if (ima == NULL) { - return; - } - - if (ibuf == NULL) { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Can't Load Image"), len - ofs); - } - else { - if (ima->source == IMA_SRC_MOVIE) { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Movie"), len - ofs); - if (BKE_image_has_anim(ima)) { - ofs += BLI_snprintf( - str + ofs, - len - ofs, - IFACE_(" %d frs"), - IMB_anim_get_duration(((ImageAnim *)ima->anims.first)->anim, IMB_TC_RECORD_RUN)); - } - } - else { - ofs += BLI_strncpy_rlen(str, IFACE_("Image"), len - ofs); - } - - ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(": size %d x %d,"), ibuf->x, ibuf->y); - - if (ibuf->rect_float) { - if (ibuf->channels != 4) { - ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_("%d float channel(s)"), ibuf->channels); - } - else if (ibuf->planes == R_IMF_PLANES_RGBA) { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA float"), len - ofs); - } - else { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB float"), len - ofs); - } - } - else { - if (ibuf->planes == R_IMF_PLANES_RGBA) { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA byte"), len - ofs); - } - else { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB byte"), len - ofs); - } - } - if (ibuf->zbuf || ibuf->zbuf_float) { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" + Z"), len - ofs); - } - - if (ima->source == IMA_SRC_SEQUENCE) { - const char *file = BLI_last_slash(ibuf->name); - if (file == NULL) { - file = ibuf->name; - } - else { - file++; - } - ofs += BLI_snprintf(str + ofs, len - ofs, ", %s", file); - } - } - - /* the frame number, even if we cant */ - if (ima->source == IMA_SRC_SEQUENCE) { - /* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */ - const int framenr = BKE_image_user_frame_get(iuser, CFRA, NULL); - ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(", Frame: %d"), framenr); - } -} - /* gets active viewer user */ struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree) { @@ -650,23 +576,6 @@ static void image_multiview_cb(bContext *C, void *rnd_pt, void *UNUSED(arg_v)) WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); } -#if 0 -static void image_freecache_cb(bContext *C, void *ima_v, void *unused) -{ - Scene *scene = CTX_data_scene(C); - BKE_image_free_anim_ibufs(ima_v, scene->r.cfra); - WM_event_add_notifier(C, NC_IMAGE, ima_v); -} -#endif - -#if 0 -static void image_user_change(bContext *C, void *iuser_v, void *unused) -{ - Scene *scene = CTX_data_scene(C); - BKE_image_user_calc_imanr(iuser_v, scene->r.cfra, 0); -} -#endif - static void uiblock_layer_pass_buttons( uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w, short *render_slot) { @@ -839,6 +748,22 @@ static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg)) RNA_property_update(C, &cb->ptr, cb->prop); } +static bool image_has_alpha(Image *ima, ImageUser *iuser) +{ + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); + if (ibuf == NULL) { + return false; + } + + int imtype = BKE_image_ftype_to_imtype(ibuf->ftype, &ibuf->foptions); + char valid_channels = BKE_imtype_valid_channels(imtype, false); + bool has_alpha = (valid_channels & IMA_CHAN_FLAG_ALPHA) != 0; + + BKE_image_release_ibuf(ima, ibuf, NULL); + + return has_alpha; +} + void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, @@ -847,23 +772,11 @@ void uiTemplateImage(uiLayout *layout, bool compact, bool multiview) { - PropertyRNA *prop; - PointerRNA imaptr; - RNAUpdateCb *cb; - Image *ima; - ImageUser *iuser; - Scene *scene = CTX_data_scene(C); - uiLayout *row, *split, *col; - uiBlock *block; - char str[MAX_IMAGE_INFO_LEN]; - - void *lock; - if (!ptr->data) { return; } - prop = RNA_struct_find_property(ptr, propname); + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); if (!prop) { printf( "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname); @@ -878,23 +791,20 @@ void uiTemplateImage(uiLayout *layout, return; } - block = uiLayoutGetBlock(layout); + uiBlock *block = uiLayoutGetBlock(layout); - imaptr = RNA_property_pointer_get(ptr, prop); - ima = imaptr.data; - iuser = userptr->data; + PointerRNA imaptr = RNA_property_pointer_get(ptr, prop); + Image *ima = imaptr.data; + ImageUser *iuser = userptr->data; + Scene *scene = CTX_data_scene(C); BKE_image_user_frame_calc(iuser, (int)scene->r.cfra); - cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb"); - cb->ptr = *ptr; - cb->prop = prop; - cb->iuser = iuser; - uiLayoutSetContextPointer(layout, "edit_image", &imaptr); uiLayoutSetContextPointer(layout, "edit_image_user", userptr); - if (!compact) { + SpaceImage *space_image = CTX_wm_space_image(C); + if (!compact && (space_image == NULL || iuser != &space_image->iuser)) { uiTemplateID(layout, C, ptr, @@ -904,217 +814,178 @@ void uiTemplateImage(uiLayout *layout, NULL, UI_TEMPLATE_ID_FILTER_ALL, false); + + if (ima != NULL) { + uiItemS(layout); + } } - if (ima) { - UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL); - - if (ima->source == IMA_SRC_VIEWER) { - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); - image_info(scene, iuser, ima, ibuf, str, MAX_IMAGE_INFO_LEN); - BKE_image_release_ibuf(ima, ibuf, lock); - - uiItemL(layout, ima->id.name + 2, ICON_NONE); - uiItemL(layout, str, ICON_NONE); - - if (ima->type == IMA_TYPE_COMPOSITE) { - // XXX not working yet -#if 0 - iuser = ntree_get_active_iuser(scene->nodetree); - if (iuser) { - UI_block_align_begin(block); - uiDefIconTextBut(block, - UI_BTYPE_BUT, - B_SIMA_RECORD, - ICON_REC, - "Record", - 10, - 120, - 100, - 20, - 0, - 0, - 0, - 0, - 0, - ""); - uiDefIconTextBut(block, - UI_BTYPE_BUT, - B_SIMA_PLAY, - ICON_PLAY, - "Play", - 110, - 120, - 100, - 20, - 0, - 0, - 0, - 0, - 0, - ""); - but = uiDefBut( - block, UI_BTYPE_BUT, B_NOP, "Free Cache", 210, 120, 100, 20, 0, 0, 0, 0, 0, ""); - UI_but_func_set(but, image_freecache_cb, ima, NULL); - - if (iuser->frames) - BLI_snprintf(str, sizeof(str), "(%d) Frames:", iuser->framenr); - else - strcpy(str, "Frames:"); - UI_block_align_begin(block); - uiDefButI(block, - UI_BTYPE_NUM, - imagechanged, - str, - 10, - 90, - 150, - 20, - &iuser->frames, - 0.0, - MAXFRAMEF, - 0, - 0, - "Number of images of a movie to use"); - uiDefButI(block, - UI_BTYPE_NUM, - imagechanged, - "StartFr:", - 160, - 90, - 150, - 20, - &iuser->sfra, - 1.0, - MAXFRAMEF, - 0, - 0, - "Global starting frame of the movie"); - } -#endif - } - else if (ima->type == IMA_TYPE_R_RESULT) { - /* browse layer/passes */ - RenderResult *rr; - const float dpi_fac = UI_DPI_FAC; - const int menus_width = 230 * dpi_fac; - - /* use BKE_image_acquire_renderresult so we get the correct slot in the menu */ - rr = BKE_image_acquire_renderresult(scene, ima); - uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot); - BKE_image_release_renderresult(scene, ima); - } + if (ima == NULL) { + return; + } + + if (ima->source == IMA_SRC_VIEWER) { + /* Viewer images. */ + uiTemplateImageInfo(layout, C, ima, iuser); + + if (ima->type == IMA_TYPE_COMPOSITE) { + } + else if (ima->type == IMA_TYPE_R_RESULT) { + /* browse layer/passes */ + RenderResult *rr; + const float dpi_fac = UI_DPI_FAC; + const int menus_width = 230 * dpi_fac; + + /* use BKE_image_acquire_renderresult so we get the correct slot in the menu */ + rr = BKE_image_acquire_renderresult(scene, ima); + uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot); + BKE_image_release_renderresult(scene, ima); + } + + return; + } + + /* Set custom callback for property updates. */ + RNAUpdateCb *cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb"); + cb->ptr = *ptr; + cb->prop = prop; + cb->iuser = iuser; + UI_block_funcN_set(block, rna_update_cb, cb, NULL); + + /* Disable editing if image was modified, to avoid losing changes. */ + const bool is_dirty = BKE_image_is_dirty(ima); + if (is_dirty) { + uiLayout *row = uiLayoutRow(layout, true); + uiItemO(row, IFACE_("Save"), ICON_NONE, "image.save"); + uiItemO(row, IFACE_("Discard"), ICON_NONE, "image.reload"); + uiItemS(layout); + } + + layout = uiLayoutColumn(layout, false); + uiLayoutSetEnabled(layout, !is_dirty); + uiLayoutSetPropDecorate(layout, false); + + /* Image source */ + { + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetPropSep(col, true); + uiItemR(col, &imaptr, "source", 0, NULL, ICON_NONE); + } + + /* Filepath */ + const bool is_packed = BKE_image_has_packedfile(ima); + const bool no_filepath = is_packed && !BKE_image_has_filepath(ima); + + if ((ima->source != IMA_SRC_GENERATED) && !no_filepath) { + uiItemS(layout); + + uiLayout *row = uiLayoutRow(layout, true); + if (is_packed) { + uiItemO(row, "", ICON_PACKAGE, "image.unpack"); } else { - uiItemR(layout, &imaptr, "source", 0, NULL, ICON_NONE); + uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack"); + } - if (ima->source != IMA_SRC_GENERATED) { - row = uiLayoutRow(layout, true); - if (BKE_image_has_packedfile(ima)) { - uiItemO(row, "", ICON_PACKAGE, "image.unpack"); - } - else { - uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack"); - } + row = uiLayoutRow(row, true); + uiLayoutSetEnabled(row, is_packed == false); + uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE); + uiItemO(row, "", ICON_FILE_REFRESH, "image.reload"); + } - row = uiLayoutRow(row, true); - uiLayoutSetEnabled(row, BKE_image_has_packedfile(ima) == false); - uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE); - uiItemO(row, "", ICON_FILE_REFRESH, "image.reload"); - } + /* Image layers and Info */ + if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) { + uiItemS(layout); - /* multilayer? */ - if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) { - const float dpi_fac = UI_DPI_FAC; - uiblock_layer_pass_buttons(layout, ima, ima->rr, iuser, 230 * dpi_fac, NULL); - } - else if (ima->source != IMA_SRC_GENERATED) { - if (compact == 0) { - uiTemplateImageInfo(layout, C, ima, iuser); - } - } + const float dpi_fac = UI_DPI_FAC; + uiblock_layer_pass_buttons(layout, ima, ima->rr, iuser, 230 * dpi_fac, NULL); + } + else if (ima->source == IMA_SRC_GENERATED) { + uiItemS(layout); - col = uiLayoutColumn(layout, false); - uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings"); - uiItemR(col, &imaptr, "use_view_as_render", 0, NULL, ICON_NONE); + /* Generated */ + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetPropSep(col, true); - if (ima->source != IMA_SRC_GENERATED) { - if (compact == 0) { /* background image view doesn't need these */ - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); - bool has_alpha = true; - - if (ibuf) { - int imtype = BKE_image_ftype_to_imtype(ibuf->ftype, &ibuf->foptions); - char valid_channels = BKE_imtype_valid_channels(imtype, false); - - has_alpha = (valid_channels & IMA_CHAN_FLAG_ALPHA) != 0; - - BKE_image_release_ibuf(ima, ibuf, NULL); - } - - if (multiview) { - if ((scene->r.scemode & R_MULTIVIEW) != 0) { - uiItemR(layout, &imaptr, "use_multiview", 0, NULL, ICON_NONE); - - if (RNA_boolean_get(&imaptr, "use_multiview")) { - uiTemplateImageViews(layout, &imaptr); - } - } - } - - if (has_alpha) { - col = uiLayoutColumn(layout, false); - uiItemR(col, &imaptr, "use_alpha", 0, NULL, ICON_NONE); - row = uiLayoutRow(col, false); - uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_alpha")); - uiItemR(row, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE); - } - - if (ima->source == IMA_SRC_MOVIE) { - col = uiLayoutColumn(layout, false); - uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE); - } - } - } + uiLayout *sub = uiLayoutColumn(col, true); + uiItemR(sub, &imaptr, "generated_width", 0, "X", ICON_NONE); + uiItemR(sub, &imaptr, "generated_height", 0, "Y", ICON_NONE); + + uiItemR(col, &imaptr, "use_generated_float", 0, NULL, ICON_NONE); + + uiItemS(col); + + uiItemR(col, &imaptr, "generated_type", UI_ITEM_R_EXPAND, IFACE_("Type"), ICON_NONE); + if (ima->gen_type == IMA_GENTYPE_BLANK) { + uiItemR(col, &imaptr, "generated_color", 0, NULL, ICON_NONE); + } + } + else if (compact == 0) { + uiTemplateImageInfo(layout, C, ima, iuser); + } + + if (BKE_image_is_animated(ima)) { + /* Animation */ + uiItemS(layout); - if (BKE_image_is_animated(ima)) { - uiItemS(layout); + uiLayout *col = uiLayoutColumn(layout, true); + uiLayoutSetPropSep(col, true); - split = uiLayoutSplit(layout, 0.0f, false); + uiLayout *sub = uiLayoutColumn(col, true); + uiLayout *row = uiLayoutRow(sub, true); + uiItemR(row, userptr, "frame_duration", 0, IFACE_("Frames"), ICON_NONE); + uiItemO(row, "", ICON_FILE_REFRESH, "IMAGE_OT_match_movie_length"); - col = uiLayoutColumn(split, false); + uiItemR(sub, userptr, "frame_start", 0, IFACE_("Start"), ICON_NONE); + uiItemR(sub, userptr, "frame_offset", 0, NULL, ICON_NONE); - BLI_snprintf(str, sizeof(str), IFACE_("(%d) Frames"), iuser->framenr); - uiItemR(col, userptr, "frame_duration", 0, str, ICON_NONE); - uiItemR(col, userptr, "frame_start", 0, IFACE_("Start"), ICON_NONE); - uiItemR(col, userptr, "frame_offset", 0, NULL, ICON_NONE); + uiItemR(col, userptr, "use_cyclic", 0, NULL, ICON_NONE); + uiItemR(col, userptr, "use_auto_refresh", 0, NULL, ICON_NONE); - col = uiLayoutColumn(split, false); - uiItemO(col, NULL, ICON_NONE, "IMAGE_OT_match_movie_length"); - uiItemR(col, userptr, "use_auto_refresh", 0, NULL, ICON_NONE); - uiItemR(col, userptr, "use_cyclic", 0, NULL, ICON_NONE); + if (ima->source == IMA_SRC_MOVIE && compact == 0) { + uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE); + } + } + + /* Multiview */ + if (multiview && compact == 0) { + if ((scene->r.scemode & R_MULTIVIEW) != 0) { + uiItemS(layout); + + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetPropSep(col, true); + uiItemR(col, &imaptr, "use_multiview", 0, NULL, ICON_NONE); + + if (RNA_boolean_get(&imaptr, "use_multiview")) { + uiTemplateImageViews(layout, &imaptr); } - else if (ima->source == IMA_SRC_GENERATED) { - split = uiLayoutSplit(layout, 0.0f, false); + } + } - col = uiLayoutColumn(split, true); - uiItemR(col, &imaptr, "generated_width", 0, "X", ICON_NONE); - uiItemR(col, &imaptr, "generated_height", 0, "Y", ICON_NONE); + /* Colorspace and alpha */ + { + uiItemS(layout); - uiItemR(col, &imaptr, "use_generated_float", 0, NULL, ICON_NONE); + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetPropSep(col, true); + uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings"); - uiItemR(split, &imaptr, "generated_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + if (compact == 0) { + if (ima->source != IMA_SRC_GENERATED) { + if (image_has_alpha(ima, iuser)) { + uiLayout *sub = uiLayoutColumn(col, false); + uiItemR(sub, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE); - if (ima->gen_type == IMA_GENTYPE_BLANK) { - uiItemR(layout, &imaptr, "generated_color", 0, NULL, ICON_NONE); + bool is_data = IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name); + uiLayoutSetActive(sub, !is_data); } } - } - UI_block_funcN_set(block, NULL, NULL, NULL); + uiItemR(col, &imaptr, "use_view_as_render", 0, NULL, ICON_NONE); + } } - MEM_freeN(cb); + UI_block_funcN_set(block, NULL, NULL, NULL); } void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_management) @@ -1327,21 +1198,87 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser) { - Scene *scene = CTX_data_scene(C); - ImBuf *ibuf; - char str[MAX_IMAGE_INFO_LEN]; + if (ima == NULL || iuser == NULL) { + return; + } + + /* Acquire image buffer. */ void *lock; + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); - if (!ima || !iuser) { - return; + uiLayout *col = uiLayoutColumn(layout, true); + uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_RIGHT); + + if (ibuf == NULL) { + uiItemL(col, IFACE_("Can't Load Image"), ICON_NONE); } + else { + char str[MAX_IMAGE_INFO_LEN] = {0}; + const int len = MAX_IMAGE_INFO_LEN; + int ofs = 0; - ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); + ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_("%d x %d, "), ibuf->x, ibuf->y); + + if (ibuf->rect_float) { + if (ibuf->channels != 4) { + ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_("%d float channel(s)"), ibuf->channels); + } + else if (ibuf->planes == R_IMF_PLANES_RGBA) { + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA float"), len - ofs); + } + else { + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB float"), len - ofs); + } + } + else { + if (ibuf->planes == R_IMF_PLANES_RGBA) { + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA byte"), len - ofs); + } + else { + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB byte"), len - ofs); + } + } + if (ibuf->zbuf || ibuf->zbuf_float) { + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" + Z"), len - ofs); + } + + uiItemL(col, str, ICON_NONE); + } + + /* Frame number, even if we can't load the image. */ + if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) { + /* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */ + Scene *scene = CTX_data_scene(C); + const int framenr = BKE_image_user_frame_get(iuser, CFRA, NULL); + char str[MAX_IMAGE_INFO_LEN]; + int duration = 0; + + if (ima->source == IMA_SRC_MOVIE && BKE_image_has_anim(ima)) { + struct anim *anim = ((ImageAnim *)ima->anims.first)->anim; + if (anim) { + duration = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN); + } + } + + if (duration > 0) { + /* Movie duration */ + BLI_snprintf(str, MAX_IMAGE_INFO_LEN, IFACE_("Frame %d / %d"), framenr, duration); + } + else if (ima->source == IMA_SRC_SEQUENCE && ibuf) { + /* Image sequence frame number + filename */ + const char *filename = BLI_last_slash(ibuf->name); + filename = (filename == NULL) ? ibuf->name : filename + 1; + BLI_snprintf(str, MAX_IMAGE_INFO_LEN, IFACE_("Frame %d: %s"), framenr, filename); + } + else { + /* Frame number */ + BLI_snprintf(str, MAX_IMAGE_INFO_LEN, IFACE_("Frame %d"), framenr); + } + + uiItemL(col, str, ICON_NONE); + } - BKE_image_user_frame_calc(iuser, (int)scene->r.cfra); - image_info(scene, iuser, ima, ibuf, str, MAX_IMAGE_INFO_LEN); BKE_image_release_ibuf(ima, ibuf, lock); - uiItemL(layout, str, ICON_NONE); } #undef MAX_IMAGE_INFO_LEN @@ -1373,6 +1310,7 @@ void image_buttons_register(ARegionType *art) strcpy(pt->label, N_("Metadata")); strcpy(pt->category, "Image"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->order = 10; pt->poll = metadata_panel_context_poll; pt->draw = metadata_panel_context_draw; pt->flag |= PNL_DEFAULT_CLOSED; diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h index a851684f2f3..2c723f45e94 100644 --- a/source/blender/editors/space_image/image_intern.h +++ b/source/blender/editors/space_image/image_intern.h @@ -66,6 +66,7 @@ void IMAGE_OT_reload(struct wmOperatorType *ot); void IMAGE_OT_save(struct wmOperatorType *ot); void IMAGE_OT_save_as(struct wmOperatorType *ot); void IMAGE_OT_save_sequence(struct wmOperatorType *ot); +void IMAGE_OT_save_all_modified(struct wmOperatorType *ot); void IMAGE_OT_pack(struct wmOperatorType *ot); void IMAGE_OT_unpack(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index cec2e1c68d9..bcea65d1634 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -34,8 +34,10 @@ #include "MEM_guardedalloc.h" -#include "BLI_math.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_math.h" +#include "BLI_string.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -179,31 +181,59 @@ static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *ar, const rctf sima_zoom_set(sima, ar, size, NULL); } -#if 0 // currently unused -static bool image_poll(bContext *C) +static Image *image_from_context(const bContext *C) { - return (CTX_data_edit_image(C) != NULL); + /* Edit image is set by templates used throughout the interface, so image + * operations work outside the image editor. */ + Image *ima = CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data; + + if (ima) { + return ima; + } + else { + /* Image editor. */ + SpaceImage *sima = CTX_wm_space_image(C); + return (sima) ? sima->image : NULL; + } } -#endif -static bool space_image_buffer_exists_poll(bContext *C) +static ImageUser *image_user_from_context(const bContext *C) { - SpaceImage *sima = CTX_wm_space_image(C); - if (sima && ED_space_image_has_buffer(sima)) { - return true; + /* Edit image user is set by templates used throughout the interface, so + * image operations work outside the image editor. */ + ImageUser *iuser = CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data; + + if (iuser) { + return iuser; + } + else { + /* Image editor. */ + SpaceImage *sima = CTX_wm_space_image(C); + return (sima) ? &sima->iuser : NULL; } - return false; } -static bool image_not_packed_poll(bContext *C) +static bool image_buffer_exists_from_context(bContext *C) { - SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); - /* Do not run 'replace' on packed images, it does not give user expected results at all. */ - if (sima && sima->image && BLI_listbase_is_empty(&sima->image->packedfiles)) { - return true; + if (ima == NULL) { + return false; } - return false; + + void *lock; + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); + const bool has_buffer = (ibuf && (ibuf->rect || ibuf->rect_float)); + BKE_image_release_ibuf(ima, ibuf, lock); + return has_buffer; +} + +static bool image_not_packed_poll(bContext *C) +{ + /* Do not run 'replace' on packed images, it does not give user expected results at all. */ + Image *ima = image_from_context(C); + return (ima && BLI_listbase_is_empty(&ima->packedfiles)); } static bool imbuf_format_writeable(const ImBuf *ibuf) @@ -214,52 +244,6 @@ static bool imbuf_format_writeable(const ImBuf *ibuf) return (BKE_image_imtype_to_ftype(im_format.imtype, &options_dummy) == ibuf->ftype); } -static bool space_image_file_exists_poll(bContext *C) -{ - if (space_image_buffer_exists_poll(C)) { - Main *bmain = CTX_data_main(C); - SpaceImage *sima = CTX_wm_space_image(C); - ImBuf *ibuf; - void *lock; - bool ret = false; - char name[FILE_MAX]; - - ibuf = ED_space_image_acquire_buffer(sima, &lock); - if (ibuf) { - BLI_strncpy(name, ibuf->name, FILE_MAX); - BLI_path_abs(name, BKE_main_blendfile_path(bmain)); - - if (BLI_exists(name) == false) { - CTX_wm_operator_poll_msg_set(C, "image file not found"); - } - else if (!BLI_file_is_writable(name)) { - CTX_wm_operator_poll_msg_set(C, "image path can't be written to"); - } - else if (!imbuf_format_writeable(ibuf)) { - CTX_wm_operator_poll_msg_set(C, "image format is read-only"); - } - else { - ret = true; - } - } - ED_space_image_release_buffer(sima, ibuf, lock); - - return ret; - } - return false; -} - -#if 0 /* UNUSED */ -static bool space_image_poll(bContext *C) -{ - SpaceImage *sima = CTX_wm_space_image(C); - if (sima && sima->image) { - return true; - } - return false; -} -#endif - bool space_image_main_region_poll(bContext *C) { SpaceImage *sima = CTX_wm_space_image(C); @@ -288,24 +272,23 @@ static bool space_image_main_area_not_uv_brush_poll(bContext *C) static bool image_sample_poll(bContext *C) { SpaceImage *sima = CTX_wm_space_image(C); - if (sima) { - Object *obedit = CTX_data_edit_object(C); - if (obedit) { - /* Disable when UV editing so it doesn't swallow all click events - * (use for setting cursor). */ - if (ED_space_image_show_uvedit(sima, obedit)) { - return false; - } - } - else if (sima->mode != SI_MODE_VIEW) { + if (sima == NULL) { + return false; + } + + Object *obedit = CTX_data_edit_object(C); + if (obedit) { + /* Disable when UV editing so it doesn't swallow all click events + * (use for setting cursor). */ + if (ED_space_image_show_uvedit(sima, obedit)) { return false; } - - return space_image_main_region_poll(C); } - else { + else if (sima->mode != SI_MODE_VIEW) { return false; } + + return true; } /********************** view pan operator *********************/ @@ -1337,7 +1320,7 @@ static int image_open_exec(bContext *C, wmOperator *op) PointerRNA imaptr; RNA_id_pointer_create(&ima->id, &imaptr); - RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, imaptr); + RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, imaptr, NULL); RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop); } @@ -1522,21 +1505,16 @@ void IMAGE_OT_open(wmOperatorType *ot) static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Image *ima = CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data; - ImageUser *iuser = CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data; + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); if (!ima || !iuser) { /* Try to get a Texture, or a SpaceImage from context... */ - SpaceImage *sima = CTX_wm_space_image(C); Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; if (tex && tex->type == TEX_IMAGE) { ima = tex->ima; iuser = &tex->iuser; } - else if (sima) { - ima = sima->image; - iuser = &sima->iuser; - } } if (!ima || !iuser || !BKE_image_has_anim(ima)) { @@ -1811,14 +1789,11 @@ static void image_save_options_to_op(ImageSaveOptions *opts, wmOperator *op) RNA_string_set(op->ptr, "filepath", opts->filepath); } -static bool save_image_op(const bContext *C, - SpaceImage *sima, - wmOperator *op, - ImageSaveOptions *opts) +static bool save_image_op(const bContext *C, wmOperator *op, ImageSaveOptions *opts) { Main *bmain = CTX_data_main(C); - Image *ima = ED_space_image(sima); - ImageUser *iuser = &sima->iuser; + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); opts->relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path")); @@ -1856,21 +1831,27 @@ static int image_save_as_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - SpaceImage *sima = CTX_wm_space_image(C); + Image *image = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); ImageSaveOptions opts; BKE_image_save_options_init(&opts, bmain, scene); /* just in case to initialize values, * these should be set on invoke or by the caller. */ - image_save_options_init(bmain, &opts, sima->image, &sima->iuser, false, false); + image_save_options_init(bmain, &opts, image, iuser, false, false); image_save_options_from_op(bmain, &opts, op); opts.do_newpath = true; - save_image_op(C, sima, op, &opts); + save_image_op(C, op, &opts); + + if (opts.save_copy == false) { + BKE_image_free_packedfiles(image); + } image_save_as_free(op); + return OPERATOR_FINISHED; } @@ -1883,8 +1864,8 @@ static bool image_save_as_check(bContext *UNUSED(C), wmOperator *op) static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Main *bmain = CTX_data_main(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = ED_space_image(sima); + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); Scene *scene = CTX_data_scene(C); ImageSaveOptions opts; PropertyRNA *prop; @@ -1897,7 +1878,7 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS BKE_image_save_options_init(&opts, bmain, scene); - if (image_save_options_init(bmain, &opts, ima, &sima->iuser, true, save_as_render) == 0) { + if (image_save_options_init(bmain, &opts, ima, iuser, true, save_as_render) == 0) { return OPERATOR_CANCELLED; } image_save_options_to_op(&opts, op); @@ -1965,20 +1946,21 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op) static bool image_save_as_poll(bContext *C) { - if (space_image_buffer_exists_poll(C)) { - if (G.is_rendering) { - /* no need to NULL check here */ - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = ED_space_image(sima); + if (!image_buffer_exists_from_context(C)) { + return false; + } - if (ima->source == IMA_SRC_VIEWER) { - CTX_wm_operator_poll_msg_set(C, "can't save image while rendering"); - return false; - } + if (G.is_rendering) { + /* no need to NULL check here */ + Image *ima = image_from_context(C); + + if (ima->source == IMA_SRC_VIEWER) { + CTX_wm_operator_poll_msg_set(C, "can't save image while rendering"); + return false; } - return true; } - return false; + + return true; } void IMAGE_OT_save_as(wmOperatorType *ot) @@ -2022,21 +2004,83 @@ void IMAGE_OT_save_as(wmOperatorType *ot) /******************** save image operator ********************/ +static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser) +{ + /* Can always repack images. */ + if (BKE_image_has_packedfile(ima)) { + return true; + } + + /* Test for valid filepath. */ + void *lock; + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); + bool ret = false; + + if (ibuf) { + Main *bmain = CTX_data_main(C); + char name[FILE_MAX]; + BLI_strncpy(name, ibuf->name, FILE_MAX); + BLI_path_abs(name, BKE_main_blendfile_path(bmain)); + + if (BLI_exists(name) == false) { + CTX_wm_operator_poll_msg_set(C, "image file not found"); + } + else if (!BLI_file_is_writable(name)) { + CTX_wm_operator_poll_msg_set(C, "image path can't be written to"); + } + else if (!imbuf_format_writeable(ibuf)) { + CTX_wm_operator_poll_msg_set(C, "image format is read-only"); + } + else { + ret = true; + } + } + + BKE_image_release_ibuf(ima, ibuf, lock); + return ret; +} + +static bool image_save_poll(bContext *C) +{ + /* Can't save if there are no pixels. */ + if (image_buffer_exists_from_context(C) == false) { + return false; + } + + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); + + /* Images without a filepath will go to save as. */ + if (!BKE_image_has_filepath(ima)) { + return true; + } + + /* Check if there is a valid file path and image format we can write. */ + return image_file_path_saveable(C, ima, iuser); +} + static int image_save_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - SpaceImage *sima = CTX_wm_space_image(C); + Image *image = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); Scene *scene = CTX_data_scene(C); ImageSaveOptions opts; + if (BKE_image_has_packedfile(image)) { + /* Save packed files to memory. */ + BKE_image_memorypack(image); + return OPERATOR_FINISHED; + } + BKE_image_save_options_init(&opts, bmain, scene); - if (image_save_options_init(bmain, &opts, sima->image, &sima->iuser, false, false) == 0) { + if (image_save_options_init(bmain, &opts, image, iuser, false, false) == 0) { return OPERATOR_CANCELLED; } image_save_options_from_op(bmain, &opts, op); if (BLI_exists(opts.filepath) && BLI_file_is_writable(opts.filepath)) { - if (save_image_op(C, sima, op, &opts)) { + if (save_image_op(C, op, &opts)) { /* report since this can be called from key-shortcuts */ BKE_reportf(op->reports, RPT_INFO, "Saved Image '%s'", opts.filepath); } @@ -2050,6 +2094,19 @@ static int image_save_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int image_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Image *ima = image_from_context(C); + + if (!BKE_image_has_packedfile(ima) && !BKE_image_has_filepath(ima)) { + WM_operator_name_call(C, "IMAGE_OT_save_as", WM_OP_INVOKE_DEFAULT, NULL); + return OPERATOR_CANCELLED; + } + else { + return image_save_exec(C, op); + } +} + void IMAGE_OT_save(wmOperatorType *ot) { /* identifiers */ @@ -2059,7 +2116,8 @@ void IMAGE_OT_save(wmOperatorType *ot) /* api callbacks */ ot->exec = image_save_exec; - ot->poll = space_image_file_exists_poll; + ot->invoke = image_save_invoke; + ot->poll = image_save_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2070,30 +2128,30 @@ void IMAGE_OT_save(wmOperatorType *ot) static int image_save_sequence_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - SpaceImage *sima = CTX_wm_space_image(C); + Image *image = image_from_context(C); ImBuf *ibuf, *first_ibuf = NULL; int tot = 0; char di[FILE_MAX]; struct MovieCacheIter *iter; - if (sima->image == NULL) { + if (image == NULL) { return OPERATOR_CANCELLED; } - if (sima->image->source != IMA_SRC_SEQUENCE) { + if (image->source != IMA_SRC_SEQUENCE) { BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences"); return OPERATOR_CANCELLED; } - if (sima->image->type == IMA_TYPE_MULTILAYER) { + if (image->type == IMA_TYPE_MULTILAYER) { BKE_report(op->reports, RPT_ERROR, "Cannot save multilayer sequences"); return OPERATOR_CANCELLED; } /* get total dirty buffers and first dirty buffer which is used for menu */ ibuf = NULL; - if (sima->image->cache != NULL) { - iter = IMB_moviecacheIter_new(sima->image->cache); + if (image->cache != NULL) { + iter = IMB_moviecacheIter_new(image->cache); while (!IMB_moviecacheIter_done(iter)) { ibuf = IMB_moviecacheIter_getImBuf(iter); if (ibuf->userflags & IB_BITMAPDIRTY) { @@ -2116,7 +2174,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op) BLI_split_dir_part(first_ibuf->name, di, sizeof(di)); BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di); - iter = IMB_moviecacheIter_new(sima->image->cache); + iter = IMB_moviecacheIter_new(image->cache); while (!IMB_moviecacheIter_done(iter)) { ibuf = IMB_moviecacheIter_getImBuf(iter); @@ -2151,7 +2209,139 @@ void IMAGE_OT_save_sequence(wmOperatorType *ot) /* api callbacks */ ot->exec = image_save_sequence_exec; - ot->poll = space_image_buffer_exists_poll; + ot->poll = image_buffer_exists_from_context; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************** save all operator **********************/ + +static bool image_should_be_saved_when_modified(Image *ima) +{ + return !ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE); +} + +static bool image_should_be_saved(Image *ima) +{ + if (BKE_image_is_dirty(ima) && + (ima->source == IMA_SRC_FILE || ima->source == IMA_SRC_GENERATED)) { + return image_should_be_saved_when_modified(ima); + } + else { + return false; + } +} + +static bool image_has_valid_path(Image *ima) +{ + return strchr(ima->name, '\\') || strchr(ima->name, '/'); +} + +bool ED_image_should_save_modified(const bContext *C) +{ + return ED_image_save_all_modified_info(C, NULL) > 0; +} + +int ED_image_save_all_modified_info(const bContext *C, ReportList *reports) +{ + Main *bmain = CTX_data_main(C); + GSet *unique_paths = BLI_gset_str_new(__func__); + + int num_saveable_images = 0; + + for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { + if (image_should_be_saved(ima)) { + if (BKE_image_has_packedfile(ima) || (ima->source == IMA_SRC_GENERATED)) { + if (ima->id.lib == NULL) { + num_saveable_images++; + } + else { + BKE_reportf(reports, + RPT_WARNING, + "Packed library image: %s from library %s can't be saved", + ima->id.name, + ima->id.lib->name); + } + } + else { + if (image_has_valid_path(ima)) { + num_saveable_images++; + if (BLI_gset_haskey(unique_paths, ima->name)) { + BKE_reportf(reports, + RPT_WARNING, + "File path used by more than one saved image: %s", + ima->name); + } + else { + BLI_gset_insert(unique_paths, BLI_strdup(ima->name)); + } + } + else { + BKE_reportf(reports, + RPT_WARNING, + "Image %s can't be saved, no valid file path: %s", + ima->id.name, + ima->name); + } + } + } + } + + BLI_gset_free(unique_paths, MEM_freeN); + return num_saveable_images; +} + +bool ED_image_save_all_modified(const bContext *C, ReportList *reports) +{ + ED_image_save_all_modified_info(C, reports); + + Main *bmain = CTX_data_main(C); + bool ok = true; + + for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { + if (image_should_be_saved(ima)) { + if (BKE_image_has_packedfile(ima) || (ima->source == IMA_SRC_GENERATED)) { + BKE_image_memorypack(ima); + } + else { + if (image_has_valid_path(ima)) { + ImageSaveOptions opts; + Scene *scene = CTX_data_scene(C); + BKE_image_save_options_init(&opts, bmain, scene); + if (image_save_options_init(bmain, &opts, ima, NULL, false, false)) { + bool saved_successfully = BKE_image_save(reports, bmain, ima, NULL, &opts); + ok = ok && saved_successfully; + } + } + } + } + } + return ok; +} + +static bool image_save_all_modified_poll(bContext *C) +{ + int num_files = ED_image_save_all_modified_info(C, NULL); + return num_files > 0; +} + +static int image_save_all_modified_exec(bContext *C, wmOperator *op) +{ + ED_image_save_all_modified(C, op->reports); + return OPERATOR_FINISHED; +} + +void IMAGE_OT_save_all_modified(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Save All Modified"; + ot->idname = "IMAGE_OT_save_all_modified"; + ot->description = "Save all modified images"; + + /* api callbacks */ + ot->exec = image_save_all_modified_exec; + ot->poll = image_save_all_modified_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2162,8 +2352,8 @@ void IMAGE_OT_save_sequence(wmOperatorType *ot) static int image_reload_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); - Image *ima = CTX_data_edit_image(C); - SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); if (!ima) { return OPERATOR_CANCELLED; @@ -2172,7 +2362,7 @@ static int image_reload_exec(bContext *C, wmOperator *UNUSED(op)) /* XXX unpackImage frees image buffers */ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD); + BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD); DEG_id_tag_update(&ima->id, 0); WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); @@ -2284,7 +2474,7 @@ static int image_new_exec(bContext *C, wmOperator *op) PointerRNA imaptr; RNA_id_pointer_create(&ima->id, &imaptr); - RNA_property_pointer_set(&data->pprop.ptr, data->pprop.prop, imaptr); + RNA_property_pointer_set(&data->pprop.ptr, data->pprop.prop, imaptr, NULL); RNA_property_update(C, &data->pprop.ptr, data->pprop.prop); } else if (sima) { @@ -2414,14 +2604,14 @@ void IMAGE_OT_new(wmOperatorType *ot) static bool image_invert_poll(bContext *C) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); return BKE_image_has_ibuf(ima, NULL); } static int image_invert_exec(bContext *C, wmOperator *op) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); SpaceImage *sima = CTX_wm_space_image(C); /* undo is supported only on image paint mode currently */ @@ -2494,7 +2684,8 @@ static int image_invert_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID; + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + BKE_image_mark_dirty(ima, ibuf); if (ibuf->mipmap[0]) { ibuf->userflags |= IB_MIPMAP_INVALID; @@ -2545,7 +2736,7 @@ void IMAGE_OT_invert(wmOperatorType *ot) static bool image_pack_test(bContext *C, wmOperator *op) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); if (!ima) { return 0; @@ -2562,7 +2753,7 @@ static bool image_pack_test(bContext *C, wmOperator *op) static int image_pack_exec(bContext *C, wmOperator *op) { struct Main *bmain = CTX_data_main(C); - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); if (!image_pack_test(C, op)) { return OPERATOR_CANCELLED; @@ -2598,7 +2789,7 @@ void IMAGE_OT_pack(wmOperatorType *ot) static int image_unpack_exec(bContext *C, wmOperator *op) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); int method = RNA_enum_get(op->ptr, "method"); /* find the suppplied image by name */ @@ -2607,7 +2798,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "id", imaname); ima = BLI_findstring(&CTX_data_main(C)->images, imaname, offsetof(ID, name) + 2); if (!ima) { - ima = CTX_data_edit_image(C); + ima = image_from_context(C); } } @@ -2638,7 +2829,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op) static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); if (RNA_struct_property_is_set(op->ptr, "id")) { return image_unpack_exec(C, op); @@ -3225,176 +3416,18 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -#if 0 /* Not ported to 2.5x yet */ -/******************** record composite operator *********************/ - -typedef struct RecordCompositeData { - wmTimer *timer; - int old_cfra; - int sfra, efra; -} RecordCompositeData; - -static int image_record_composite_apply(bContext *C, wmOperator *op) -{ - SpaceImage *sima = CTX_wm_space_image(C); - RecordCompositeData *rcd = op->customdata; - Scene *scene = CTX_data_scene(C); - ImBuf *ibuf; - - WM_cursor_time(CTX_wm_window(C), scene->r.cfra); - - // XXX scene->nodetree->test_break = BKE_blender_test_break; - // XXX scene->nodetree->test_break = NULL; - - BKE_image_all_free_anim_ibufs(scene->r.cfra); - ntreeCompositExecTree(scene->nodetree, - &scene->r, - 0, - scene->r.cfra != rcd->old_cfra, - &scene->view_settings, - &scene->display_settings); /* 1 is no previews */ - - ED_area_tag_redraw(CTX_wm_area(C)); - - ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, NULL); - /* save memory in flipbooks */ - if (ibuf) - imb_freerectfloatImBuf(ibuf); - - BKE_image_release_ibuf(sima->image, ibuf, NULL); - - scene->r.cfra++; - - return (scene->r.cfra <= rcd->efra); -} - -static int image_record_composite_init(bContext *C, wmOperator *op) -{ - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - RecordCompositeData *rcd; - - if (sima->iuser.frames < 2) - return 0; - if (scene->nodetree == NULL) - return 0; - - op->customdata = rcd = MEM_callocN(sizeof(RecordCompositeData), "ImageRecordCompositeData"); - - rcd->old_cfra = scene->r.cfra; - rcd->sfra = sima->iuser.sfra; - rcd->efra = sima->iuser.sfra + sima->iuser.frames - 1; - scene->r.cfra = rcd->sfra; - - return 1; -} - -static void image_record_composite_exit(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - SpaceImage *sima = CTX_wm_space_image(C); - RecordCompositeData *rcd = op->customdata; - - scene->r.cfra = rcd->old_cfra; - - WM_cursor_modal_restore(CTX_wm_window(C)); - - if (rcd->timer) - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rcd->timer); - - WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image); - - // XXX play_anim(0); - // XXX allqueue(REDRAWNODE, 1); - - MEM_freeN(rcd); -} - -static int image_record_composite_exec(bContext *C, wmOperator *op) -{ - if (!image_record_composite_init(C, op)) - return OPERATOR_CANCELLED; - - while (image_record_composite_apply(C, op)) { - } - - image_record_composite_exit(C, op); - - return OPERATOR_FINISHED; -} - -static int image_record_composite_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - RecordCompositeData *rcd; - - if (!image_record_composite_init(C, op)) - return OPERATOR_CANCELLED; - - rcd = op->customdata; - rcd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.0f); - WM_event_add_modal_handler(C, op); - - if (!image_record_composite_apply(C, op)) - return OPERATOR_FINISHED; - - return OPERATOR_RUNNING_MODAL; -} - -static int image_record_composite_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - RecordCompositeData *rcd = op->customdata; - - switch (event->type) { - case TIMER: - if (rcd->timer == event->customdata) { - if (!image_record_composite_apply(C, op)) { - image_record_composite_exit(C, op); - return OPERATOR_FINISHED; - } - } - break; - case ESCKEY: - image_record_composite_exit(C, op); - return OPERATOR_FINISHED; - } - - return OPERATOR_RUNNING_MODAL; -} - -static void image_record_composite_cancel(bContext *C, wmOperator *op) -{ - image_record_composite_exit(C, op); - return OPERATOR_CANCELLED; -} - -void IMAGE_OT_record_composite(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Record Composite"; - ot->idname = "IMAGE_OT_record_composite"; - - /* api callbacks */ - ot->exec = image_record_composite_exec; - ot->invoke = image_record_composite_invoke; - ot->modal = image_record_composite_modal; - ot->cancel = image_record_composite_cancel; - ot->poll = space_image_buffer_exists_poll; -} - -#endif - /********************* cycle render slot operator *********************/ static bool image_cycle_render_slot_poll(bContext *C) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); return (ima && ima->type == IMA_TYPE_R_RESULT); } static int image_cycle_render_slot_exec(bContext *C, wmOperator *op) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); const int direction = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1; if (!ED_image_slot_cycle(ima, direction)) { @@ -3434,7 +3467,7 @@ void IMAGE_OT_cycle_render_slot(wmOperatorType *ot) static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); if (!BKE_image_clear_renderslot(ima, &sima->iuser, ima->render_slot)) { return OPERATOR_CANCELLED; @@ -3464,7 +3497,7 @@ void IMAGE_OT_clear_render_slot(wmOperatorType *ot) static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op)) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); RenderSlot *slot = BKE_image_add_renderslot(ima, NULL); ima->render_slot = BLI_findindex(&ima->renderslots, slot); @@ -3494,7 +3527,7 @@ void IMAGE_OT_add_render_slot(wmOperatorType *ot) static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); if (!BKE_image_remove_renderslot(ima, &sima->iuser, ima->render_slot)) { return OPERATOR_CANCELLED; diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 386e258a833..a8be93ad213 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -224,6 +224,7 @@ static void image_operatortypes(void) WM_operatortype_append(IMAGE_OT_save); WM_operatortype_append(IMAGE_OT_save_as); WM_operatortype_append(IMAGE_OT_save_sequence); + WM_operatortype_append(IMAGE_OT_save_all_modified); WM_operatortype_append(IMAGE_OT_pack); WM_operatortype_append(IMAGE_OT_unpack); @@ -567,7 +568,8 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) Object *obedit = CTX_data_edit_object(C); Depsgraph *depsgraph = CTX_data_depsgraph(C); Mask *mask = NULL; - bool curve = false; + bool show_uvedit = false; + bool show_curve = false; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); View2D *v2d = &ar->v2d; @@ -609,13 +611,13 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) /* check for mask (delay draw) */ if (ED_space_image_show_uvedit(sima, obedit)) { - /* pass */ + show_uvedit = true; } else if (sima->mode == SI_MODE_MASK) { mask = ED_space_image_get_mask(sima); } else if (ED_space_image_paint_curve(C)) { - curve = true; + show_curve = true; } ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); @@ -669,12 +671,9 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) false, NULL, C); - - UI_view2d_view_ortho(v2d); - ED_image_draw_cursor(ar, sima->cursor); - UI_view2d_view_restore(C); } - else if (curve) { + + if (show_uvedit || mask || show_curve) { UI_view2d_view_ortho(v2d); ED_image_draw_cursor(ar, sima->cursor); UI_view2d_view_restore(C); @@ -764,7 +763,7 @@ static void image_buttons_region_layout(const bContext *C, ARegion *ar) } const bool vertical = true; - ED_region_panels_layout_ex(C, ar, contexts_base, -1, vertical); + ED_region_panels_layout_ex(C, ar, &ar->type->paneltypes, contexts_base, -1, vertical, NULL); } static void image_buttons_region_draw(const bContext *C, ARegion *ar) @@ -1035,9 +1034,10 @@ void ED_spacetype_image(void) /* regions: listview/buttons/scopes */ art = MEM_callocN(sizeof(ARegionType), "spacetype image region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 220; // XXX + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = image_buttons_region_listener; + art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_ui; art->init = image_buttons_region_init; art->layout = image_buttons_region_layout; art->draw = image_buttons_region_draw; diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c index 171d8505222..bf43e493cc5 100644 --- a/source/blender/editors/space_info/info_ops.c +++ b/source/blender/editors/space_info/info_ops.c @@ -160,19 +160,11 @@ static int pack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(ev { Main *bmain = CTX_data_main(C); Image *ima; - ImBuf *ibuf; // first check for dirty images for (ima = bmain->images.first; ima; ima = ima->id.next) { - if (BKE_image_has_loaded_ibuf(ima)) { /* XXX FIX */ - ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY)) { - BKE_image_release_ibuf(ima, ibuf, NULL); - break; - } - - BKE_image_release_ibuf(ima, ibuf, NULL); + if (BKE_image_is_dirty(ima)) { + break; } } diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 4115d6b49ba..e5c116e85de 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -52,6 +52,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "UI_interface.h" + #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -384,19 +386,12 @@ static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEv selectmode = SELECT_REPLACE; } - /** - * Figure out which channel user clicked in: - * - * \note Although channels technically start at y= NLACHANNEL_FIRST, - * we need to adjust by half a channel's height so that the tops of channels get caught ok. - * Since NLACHANNEL_FIRST is really NLACHANNEL_HEIGHT, we simply use NLACHANNEL_HEIGHT_HALF. - */ + /* Figure out which channel user clicked in. */ UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y); - UI_view2d_listview_view_to_cell(v2d, - NLACHANNEL_NAMEWIDTH, + UI_view2d_listview_view_to_cell(NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, - (float)NLACHANNEL_HEIGHT_HALF(snla), + NLACHANNEL_FIRST_TOP(&ac), x, y, NULL, diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 1df2190b7af..68cbfd76331 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -689,23 +689,19 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) * - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for * start of list offset, and the second is as a correction for the scrollers. */ - int height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2)); - - /* don't use totrect set, as the width stays the same - * (NOTE: this is ok here, the configuration is pretty straightforward) - */ - v2d->tot.ymin = (float)(-height); + int height = NLACHANNEL_TOT_HEIGHT(ac, items); + v2d->tot.ymin = -height; /* loop through channels, and set up drawing depending on their type */ - float y = (float)(-NLACHANNEL_HEIGHT(snla)); + float ymax = NLACHANNEL_FIRST_TOP(ac); - for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla)); - const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla)); + for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next, ymax -= NLACHANNEL_STEP(snla)) { + float ymin = ymax - NLACHANNEL_HEIGHT(snla); + float ycenter = (ymax + ymin) / 2.0f; /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* data to draw depends on the type of channel */ switch (ale->type) { case ANIMTYPE_NLATRACK: { @@ -721,18 +717,18 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) const float xmaxc = strip->end + text_margin_x; /* draw the visualization of the strip */ - nla_draw_strip(snla, adt, nlt, strip, v2d, yminc, ymaxc); + nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax); /* add the text for this strip to the cache */ if (xminc < xmaxc) { - nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, yminc, ymaxc); + nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, ymin, ymax); } /* if transforming strips (only real reason for temp-metas currently), * add to the cache the frame numbers of the strip's extents */ if (strip->flag & NLASTRIP_FLAG_TEMP_META) { - nla_draw_strip_frames_text(nlt, strip, v2d, yminc, ymaxc); + nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax); } } } @@ -761,27 +757,27 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) * but also slightly shorter for some more contrast when viewing the strips */ immRectf( - pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); + pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP, v2d->cur.xmax, ymax - NLACHANNEL_SKIP); /* draw 'embossed' lines above and below the strip for effect */ /* white base-lines */ GPU_line_width(2.0f); immUniformColor4f(1.0f, 1.0f, 1.0f, 0.3f); immBegin(GPU_PRIM_LINES, 4); - immVertex2f(pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmax, yminc + NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, ymin + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmin, ymax - NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, ymax - NLACHANNEL_SKIP); immEnd(); /* black top-lines */ GPU_line_width(1.0f); immUniformColor3f(0.0f, 0.0f, 0.0f); immBegin(GPU_PRIM_LINES, 4); - immVertex2f(pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmax, yminc + NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, ymin + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmin, ymax - NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, ymax - NLACHANNEL_SKIP); immEnd(); /* TODO: these lines but better --^ */ @@ -790,16 +786,13 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) /* draw keyframes in the action */ nla_action_draw_keyframes( - v2d, adt, ale->data, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP); + v2d, adt, ale->data, ycenter, ymin + NLACHANNEL_SKIP, ymax - NLACHANNEL_SKIP); GPU_blend(false); break; } } } - - /* adjust y-position for next one */ - y -= NLACHANNEL_STEP(snla); } /* free tempolary channels */ @@ -817,7 +810,6 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) SpaceNla *snla = (SpaceNla *)ac->sl; View2D *v2d = &ar->v2d; - float y = 0.0f; size_t items; /* build list of channels to draw */ @@ -830,11 +822,9 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) * - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for * start of list offset, and the second is as a correction for the scrollers. */ - int height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2)); - /* don't use totrect set, as the width stays the same - * (NOTE: this is ok here, the configuration is pretty straightforward) - */ - v2d->tot.ymin = (float)(-height); + int height = NLACHANNEL_TOT_HEIGHT(ac, items); + v2d->tot.ymin = -height; + /* need to do a view-sync here, so that the keys area doesn't jump around * (it must copy this) */ UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY); @@ -842,30 +832,24 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) /* draw channels */ { /* first pass: just the standard GL-drawing for backdrop + text */ size_t channel_index = 0; + float ymax = NLACHANNEL_FIRST_TOP(ac); - y = (float)(-NLACHANNEL_HEIGHT(snla)); - - for (ale = anim_data.first; ale; ale = ale->next) { - float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla)); - float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla)); + for (ale = anim_data.first; ale; + ale = ale->next, ymax -= NLACHANNEL_STEP(snla), channel_index++) { + float ymin = ymax - NLACHANNEL_HEIGHT(snla); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ - ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index); + ANIM_channel_draw(ac, ale, ymin, ymax, channel_index); } - - /* adjust y-position for next one */ - y -= NLACHANNEL_STEP(snla); - channel_index++; } } { /* second pass: UI widgets */ uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); size_t channel_index = 0; - - y = (float)(-NLACHANNEL_HEIGHT(snla)); + float ymax = NLACHANNEL_FIRST_TOP(ac); /* set blending again, as may not be set in previous step */ GPU_blend_set_func_separate( @@ -873,22 +857,18 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) GPU_blend(true); /* loop through channels, and set up drawing depending on their type */ - for (ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla)); - const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla)); + for (ale = anim_data.first; ale; + ale = ale->next, ymax -= NLACHANNEL_STEP(snla), channel_index++) { + float ymin = ymax - NLACHANNEL_HEIGHT(snla); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ rctf channel_rect; - BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, yminc, ymaxc); + BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, ymin, ymax); ANIM_channel_draw_widgets(C, ac, ale, block, &channel_rect, channel_index); } - - /* adjust y-position for next one */ - y -= NLACHANNEL_STEP(snla); - channel_index++; } UI_block_end(C, block); diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 0446235a776..acb3d913114 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -421,27 +421,25 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, floa int filter; SpaceNla *snla = (SpaceNla *)ac->sl; - const float half_height = NLACHANNEL_HEIGHT_HALF(snla); /* NOTE: not bool, since we want prioritise individual channels over expanders */ short found = 0; - float y; /* get all items - we need to do it this way */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop through all channels, finding the first one that's selected */ - y = (float)NLACHANNEL_FIRST; + float ymax = NLACHANNEL_FIRST_TOP(ac); - for (ale = anim_data.first; ale; ale = ale->next) { + for (ale = anim_data.first; ale; ale = ale->next, ymax -= NLACHANNEL_STEP(snla)) { const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); /* must be selected... */ if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) && ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT)) { /* update best estimate */ - *min = (float)(y - half_height); - *max = (float)(y + half_height); + *min = ymax - NLACHANNEL_HEIGHT(snla); + *max = ymax; /* is this high enough priority yet? */ found = acf->channel_role; @@ -453,9 +451,6 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, floa break; } } - - /* adjust y-position for next one */ - y -= NLACHANNEL_STEP(snla); } /* free all temp data */ @@ -2451,6 +2446,7 @@ void NLA_OT_fmodifier_add(wmOperatorType *ot) /* id-props */ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", ""); + RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ACTION); RNA_def_enum_funcs(ot->prop, nla_fmodifier_itemf); RNA_def_boolean(ot->srna, diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c index 5c9e48f3d5d..0de9acfec25 100644 --- a/source/blender/editors/space_nla/nla_select.c +++ b/source/blender/editors/space_nla/nla_select.c @@ -47,6 +47,7 @@ #include "WM_types.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "nla_intern.h" // own include @@ -541,15 +542,8 @@ static void mouse_nla_strips( /* use View2D to determine the index of the channel * (i.e a row in the list) where keyframe was */ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); - UI_view2d_listview_view_to_cell(v2d, - 0, - NLACHANNEL_STEP(snla), - 0, - (float)NLACHANNEL_HEIGHT_HALF(snla), - x, - y, - NULL, - &channel_index); + UI_view2d_listview_view_to_cell( + 0, NLACHANNEL_STEP(snla), 0, NLACHANNEL_FIRST_TOP(ac), x, y, NULL, &channel_index); /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click * (that is the size of keyframe icons, so user should be expecting similar tolerances) diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index b054f550c6c..4b7dfe5d653 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -40,6 +40,7 @@ #include "ED_anim_api.h" #include "ED_markers.h" #include "ED_screen.h" +#include "ED_time_scrub_ui.h" #include "WM_api.h" #include "WM_types.h" @@ -47,6 +48,7 @@ #include "RNA_access.h" +#include "UI_interface.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -69,6 +71,7 @@ static SpaceLink *nla_new(const ScrArea *sa, const Scene *scene) /* set auto-snapping settings */ snla->autosnap = SACTSNAP_FRAME; + snla->flag = SNLA_SHOW_MARKER_LINES; /* header */ ar = MEM_callocN(sizeof(ARegion), "header for nla"); @@ -116,7 +119,7 @@ static SpaceLink *nla_new(const ScrArea *sa, const Scene *scene) ar->v2d.minzoom = 0.01f; ar->v2d.maxzoom = 50; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); ar->v2d.scroll |= (V2D_SCROLL_RIGHT); ar->v2d.keepzoom = V2D_LOCKZOOM_Y; ar->v2d.keepofs = V2D_KEEPOFS_Y; @@ -201,6 +204,9 @@ static void nla_channel_region_draw(const bContext *C, ARegion *ar) draw_nla_channel_list(C, &ac, ar); } + /* channel filter next to scrubbing area */ + ED_channel_search_draw(C, ar, ac.ads); + /* reset view matrix */ UI_view2d_view_restore(C); @@ -284,20 +290,12 @@ static void nla_main_region_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + ED_scrubbing_draw(ar, scene, snla->flag & SNLA_DRAWTIME, true); + /* scrollers */ scrollers = UI_view2d_scrollers_calc(v2d, NULL); UI_view2d_scrollers_draw(v2d, scrollers); UI_view2d_scrollers_free(scrollers); - - /* frame numbers */ - UI_view2d_draw_scale_x__discrete_frames_or_seconds( - ar, v2d, &v2d->hor, scene, snla->flag & SNLA_DRAWTIME); - - /* draw current frame number-indicator on top of scrollers */ - if ((snla->flag & SNLA_NODRAWCFRANUM) == 0) { - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); - } } /* add handlers, stuff you only do once or on area/region changes */ @@ -614,7 +612,7 @@ void ED_spacetype_nla(void) art->draw = nla_main_region_draw; art->listener = nla_main_region_listener; art->message_subscribe = nla_main_region_message_subscribe; - art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; + art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; BLI_addhead(&st->regiontypes, art); @@ -645,7 +643,7 @@ void ED_spacetype_nla(void) /* regions: UI buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype nla region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 200; + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI; art->listener = nla_region_listener; art->init = nla_buttons_region_init; diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 447fea8098c..e39e024e44a 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -708,6 +708,16 @@ static void node_buts_image_user(uiLayout *layout, col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE); } + + uiLayout *split = uiLayoutSplit(layout, 0.5f, true); + PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings"); + uiItemL(split, IFACE_("Color Space"), ICON_NONE); + uiItemR(split, &colorspace_settings_ptr, "name", 0, "", ICON_NONE); + + /* Avoid losing changes image is painted. */ + if (BKE_image_is_dirty(imaptr->data)) { + uiLayoutSetEnabled(split, false); + } } static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -782,7 +792,6 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA NULL, UI_TEMPLATE_ID_FILTER_ALL, false); - uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); @@ -820,11 +829,10 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin UI_TEMPLATE_ID_FILTER_ALL, false); - node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); - - uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); + + node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); } static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -875,7 +883,6 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P uiTemplateImageInfo(layout, C, ima, iuserptr.data); } - uiItemR(layout, ptr, "color_space", 0, IFACE_("Color Space"), ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE); uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE); } diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index 714ed707e18..01a30f677a3 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -521,7 +521,7 @@ static int new_node_tree_exec(bContext *C, wmOperator *op) id_us_min(&ntree->id); RNA_id_pointer_create(&ntree->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } else if (snode) { diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 3e73cc52c52..fb34d9dc459 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -453,13 +453,8 @@ void ED_node_shader_default(const bContext *C, ID *id) output_type = SH_NODE_OUTPUT_LIGHT; shader_type = SH_NODE_EMISSION; - copy_v3_v3(color, &la->r); - if (la->type == LA_LOCAL || la->type == LA_SPOT || la->type == LA_AREA) { - strength = 100.0f; - } - else { - strength = 1.0f; - } + copy_v3_fl3(color, 1.0f, 1.0f, 1.0f); + strength = 1.0f; break; } default: diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index b52d1d3b78f..a8331c26ce6 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -429,19 +429,24 @@ void node_select_single(bContext *C, bNode *node) WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); } -static int node_mouse_select(Main *bmain, - SpaceNode *snode, - ARegion *ar, +static int node_mouse_select(bContext *C, const int mval[2], const bool extend, const bool socket_select, - const bool deselect_all) + const bool deselect_all, + const bool wait_to_deselect_others) { + Main *bmain = CTX_data_main(C); + SpaceNode *snode = CTX_wm_space_node(C); + ARegion *ar = CTX_wm_region(C); bNode *node, *tnode; bNodeSocket *sock = NULL; bNodeSocket *tsock; float cursor[2]; - bool selected = false; + int ret_value = OPERATOR_CANCELLED; + + /* Waiting to deselect others is only allowed for basic selection. */ + BLI_assert(!(extend || socket_select) || !wait_to_deselect_others); /* get mouse coordinates in view2d space */ UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &cursor[0], &cursor[1]); @@ -449,89 +454,114 @@ static int node_mouse_select(Main *bmain, /* first do socket selection, these generally overlap with nodes. */ if (socket_select) { if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { - node_socket_toggle(node, sock, 1); - selected = true; + /* NOTE: SOCK_IN does not take into account the extend case... + * This feature is not really used anyway currently? */ + node_socket_toggle(node, sock, true); + ret_value = OPERATOR_FINISHED; } else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { if (sock->flag & SELECT) { if (extend) { - node_socket_deselect(node, sock, 1); + node_socket_deselect(node, sock, true); } else { - selected = true; + ret_value = OPERATOR_FINISHED; } } else { - /* only allow one selected output per node, for sensible linking. - * allows selecting outputs from different nodes though. */ + /* Only allow one selected output per node, for sensible linking. + * Allow selecting outputs from different nodes though, if extend is true. */ if (node) { for (tsock = node->outputs.first; tsock; tsock = tsock->next) { - node_socket_deselect(node, tsock, 1); + if (tsock == sock) { + continue; + } + node_socket_deselect(node, tsock, true); } } - if (extend) { - /* only allow one selected output per node, for sensible linking. - * allows selecting outputs from different nodes though. */ - for (tsock = node->outputs.first; tsock; tsock = tsock->next) { - if (tsock != sock) { - node_socket_deselect(node, tsock, 1); + if (!extend) { + for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { + if (tnode == node) { + continue; + } + for (tsock = tnode->outputs.first; tsock; tsock = tsock->next) { + node_socket_deselect(tnode, tsock, true); } } } node_socket_select(node, sock); - selected = true; + ret_value = OPERATOR_FINISHED; } } } - if (!sock) { - if (extend) { - /* find the closest visible node */ - node = node_under_mouse_select(snode->edittree, cursor[0], cursor[1]); + /* In case we do two-steps selection, we do not want to select the node if some valid socket + * is below the mouse, as that would prevent draging from sockets (NODE_OT_link) + * to be properly triggered. See T64660. */ + if (wait_to_deselect_others) { + if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN) || + node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { + ret_value = OPERATOR_CANCELLED; + } + } - if (node) { - if ((node->flag & SELECT) && (node->flag & NODE_ACTIVE) == 0) { - /* if node is selected but not active make it active */ - ED_node_set_active(bmain, snode->edittree, node); - } - else { + if (sock == NULL) { + /* find the closest visible node */ + node = node_under_mouse_select(snode->edittree, (int)cursor[0], (int)cursor[1]); + + if (extend) { + if (node != NULL) { + /* If node is selected but not active, we want to make it active, + * but not toggle (deselect) it. */ + if (!((node->flag & SELECT) && (node->flag & NODE_ACTIVE) == 0)) { node_toggle(node); - ED_node_set_active(bmain, snode->edittree, node); } - selected = true; + ret_value = OPERATOR_FINISHED; } } - else { - /* find the closest visible node */ - node = node_under_mouse_select(snode->edittree, cursor[0], cursor[1]); + else if (deselect_all && node == NULL) { + /* Deselect in empty space. */ + for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { + nodeSetSelected(tnode, false); + } + ret_value = OPERATOR_FINISHED; + } + else if (node != NULL) { + /* When clicking on an already selected node, we want to wait to deselect + * others and allow the user to start moving the node without that. */ + if (wait_to_deselect_others && (node->flag & SELECT)) { + ret_value = OPERATOR_RUNNING_MODAL; + } + else { + nodeSetSelected(node, true); - if (node != NULL || deselect_all) { for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { - nodeSetSelected(tnode, false); - } - selected = true; - if (node != NULL) { - nodeSetSelected(node, true); - ED_node_set_active(bmain, snode->edittree, node); + if (tnode != node) { + nodeSetSelected(tnode, false); + } } + + ret_value = OPERATOR_FINISHED; } } } /* update node order */ - if (selected) { + if (ret_value != OPERATOR_CANCELLED) { + if (node != NULL && ret_value != OPERATOR_RUNNING_MODAL) { + ED_node_set_active(bmain, snode->edittree, node); + } ED_node_set_active_viewer_key(snode); ED_node_sort(snode->edittree); + + WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); } - return selected; + return ret_value; } static int node_select_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - SpaceNode *snode = CTX_wm_space_node(C); - ARegion *ar = CTX_wm_region(C); int mval[2]; /* get settings from RNA properties for operator */ @@ -544,17 +574,70 @@ static int node_select_exec(bContext *C, wmOperator *op) const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); /* perform the select */ - if (node_mouse_select(bmain, snode, ar, mval, extend, socket_select, deselect_all)) { - /* send notifiers */ - WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); + const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false); + + /* allow tweak event to work too */ + return ret_value | OPERATOR_PASS_THROUGH; +} + +static int node_select_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + const short init_event_type = (short)POINTER_AS_INT(op->customdata); + + /* get settings from RNA properties for operator */ + int mval[2]; + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); + + const bool extend = RNA_boolean_get(op->ptr, "extend"); + /* always do socket_select when extending selection. */ + const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select"); + const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); - /* allow tweak event to work too */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + /* These cases are never modal. */ + if (extend || socket_select) { + return node_select_exec(C, op); } - else { - /* allow tweak event to work too */ - return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + + if (init_event_type == 0) { + if (event->val == KM_PRESS) { + const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, true); + + op->customdata = POINTER_FROM_INT((int)event->type); + if (ret_value & OPERATOR_RUNNING_MODAL) { + WM_event_add_modal_handler(C, op); + } + return ret_value | OPERATOR_PASS_THROUGH; + } + else { + /* If we are in init phase, and cannot validate init of modal operations, + * just fall back to basic exec. + */ + return node_select_exec(C, op); + } } + else if (event->type == init_event_type && event->val == KM_RELEASE) { + const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false); + return ret_value | OPERATOR_PASS_THROUGH; + } + else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + const int dx = mval[0] - event->mval[0]; + const int dy = mval[1] - event->mval[1]; + const float tweak_threshold = U.tweak_threshold * U.dpi_fac; + /* If user moves mouse more than defined threshold, we consider select operator as + * finished. Otherwise, it is still running until we get an 'release' event. In any + * case, we pass through event, but select op is not finished yet. */ + if (abs(dx) + abs(dy) > tweak_threshold) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + } + else { + /* Important not to return anything other than PASS_THROUGH here, + * otherwise it prevents underlying tweak detection code to work properly. */ + return OPERATOR_PASS_THROUGH; + } + } + + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; } static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -562,7 +645,9 @@ static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) RNA_int_set(op->ptr, "mouse_x", event->mval[0]); RNA_int_set(op->ptr, "mouse_y", event->mval[1]); - return node_select_exec(C, op); + op->customdata = POINTER_FROM_INT(0); + + return node_select_modal(C, op, event); } void NODE_OT_select(wmOperatorType *ot) @@ -575,6 +660,7 @@ void NODE_OT_select(wmOperatorType *ot) /* api callbacks */ ot->invoke = node_select_invoke; ot->exec = node_select_exec; + ot->modal = node_select_modal; ot->poll = ED_operator_node_active; /* flags */ @@ -1186,7 +1272,7 @@ static uiBlock *node_find_menu(bContext *C, ARegion *ar, void *arg_op) static int node_find_node_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - UI_popup_block_invoke(C, node_find_menu, op); + UI_popup_block_invoke(C, node_find_menu, op, NULL); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 2152bb9847a..7183512a5bc 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -998,9 +998,10 @@ void ED_spacetype_node(void) /* regions: listview/buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 180; // XXX + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = node_region_listener; + art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_ui; art->init = node_buttons_region_init; art->draw = node_buttons_region_draw; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 6da42ecb3c0..21e54a29fb9 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -855,7 +855,7 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot) { /* identifiers */ - ot->name = "Set Exclude"; + ot->name = "Disable from View Layer"; ot->idname = "OUTLINER_OT_collection_exclude_set"; ot->description = "Exclude collection from the active view layer"; @@ -870,7 +870,7 @@ void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot) void OUTLINER_OT_collection_exclude_clear(wmOperatorType *ot) { /* identifiers */ - ot->name = "Clear Exclude"; + ot->name = "Enable in View Layer"; ot->idname = "OUTLINER_OT_collection_exclude_clear"; ot->description = "Include collection in the active view layer"; @@ -965,8 +965,8 @@ static int collection_isolate_exec(bContext *C, wmOperator *op) LayerCollection *lc_master = view_layer->layer_collections.first; for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { - lc_iter->flag |= LAYER_COLLECTION_RESTRICT_VIEW; - layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW); + lc_iter->flag |= LAYER_COLLECTION_HIDE; + layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_HIDE); } } @@ -1023,12 +1023,12 @@ void OUTLINER_OT_collection_isolate(wmOperatorType *ot) static bool collection_show_poll(bContext *C) { - return collections_view_layer_poll(C, true, LAYER_COLLECTION_RESTRICT_VIEW); + return collections_view_layer_poll(C, true, LAYER_COLLECTION_HIDE); } static bool collection_hide_poll(bContext *C) { - return collections_view_layer_poll(C, false, LAYER_COLLECTION_RESTRICT_VIEW); + return collections_view_layer_poll(C, false, LAYER_COLLECTION_HIDE); } static bool collection_inside_poll(bContext *C) @@ -1163,12 +1163,12 @@ static bool collection_flag_poll(bContext *C, bool clear, int flag) static bool collection_enable_poll(bContext *C) { - return collection_flag_poll(C, true, COLLECTION_RESTRICT_VIEW); + return collection_flag_poll(C, true, COLLECTION_RESTRICT_VIEWPORT); } static bool collection_disable_poll(bContext *C) { - return collection_flag_poll(C, false, COLLECTION_RESTRICT_VIEW); + return collection_flag_poll(C, false, COLLECTION_RESTRICT_VIEWPORT); } static bool collection_enable_render_poll(bContext *C) @@ -1188,7 +1188,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op) SpaceOutliner *soops = CTX_wm_space_outliner(C); const bool is_render = strstr(op->idname, "render"); const bool clear = strstr(op->idname, "show") || strstr(op->idname, "enable"); - int flag = is_render ? COLLECTION_RESTRICT_RENDER : COLLECTION_RESTRICT_VIEW; + int flag = is_render ? COLLECTION_RESTRICT_RENDER : COLLECTION_RESTRICT_VIEWPORT; struct CollectionEditData data = { .scene = scene, .soops = soops, @@ -1215,7 +1215,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op) /* Make sure (at least for this view layer) the collection is visible. */ if (clear && !is_render) { - layer_collection->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; + layer_collection->flag &= ~LAYER_COLLECTION_HIDE; } } BLI_gset_free(data.collections_to_edit, NULL); @@ -1408,8 +1408,8 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op)) LayerCollection *lc_master = view_layer->layer_collections.first; for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { - lc_iter->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; - layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW); + lc_iter->flag &= ~LAYER_COLLECTION_HIDE; + layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_HIDE); } /* Unhide all objects. */ diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index b556f58a02d..aed7af3911f 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -270,127 +270,413 @@ static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void } } -static int base_pushed_state_cb(bContext *UNUSED(C), void *poin) +static void outliner_object_set_flag_recursive_cb(bContext *C, + Base *base, + Object *ob, + const char *propname) +{ + Main *bmain = CTX_data_main(C); + wmWindow *win = CTX_wm_window(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + PointerRNA ptr; + + bool extend = (win->eventstate->shift != 0); + + if (!extend) { + return; + } + + /* Create PointerRNA and PropertyRNA for either Object or Base. */ + ID *id = ob ? &ob->id : &scene->id; + StructRNA *struct_rna = ob ? &RNA_Object : &RNA_ObjectBase; + void *data = ob ? (void *)ob : (void *)base; + + RNA_pointer_create(id, struct_rna, data, &ptr); + PropertyRNA *base_or_object_prop = RNA_struct_type_find_property(struct_rna, propname); + const bool value = RNA_property_boolean_get(&ptr, base_or_object_prop); + + Object *ob_parent = ob ? ob : base->object; + + for (Object *ob_iter = bmain->objects.first; ob_iter; ob_iter = ob_iter->id.next) { + if (BKE_object_is_child_recursive(ob_parent, ob_iter)) { + if (ob) { + RNA_id_pointer_create(&ob_iter->id, &ptr); + DEG_id_tag_update(&ob_iter->id, ID_RECALC_COPY_ON_WRITE); + } + else { + Base *base_iter = BKE_view_layer_base_find(view_layer, ob_iter); + RNA_pointer_create(&scene->id, &RNA_ObjectBase, base_iter, &ptr); + } + RNA_property_boolean_set(&ptr, base_or_object_prop, value); + } + } + + /* We don't call RNA_property_update() due to performance, so we batch update them. */ + if (ob) { + BKE_main_collection_sync_remap(bmain); + DEG_relations_tag_update(bmain); + } + else { + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + } +} + +/** + * Object properties. + * */ +static void outliner__object_set_flag_recursive_cb(bContext *C, void *poin, void *poin2) +{ + Object *ob = poin; + char *propname = poin2; + outliner_object_set_flag_recursive_cb(C, NULL, ob, propname); +} + +/** + * Base properties. + * */ +static void outliner__base_set_flag_recursive_cb(bContext *C, void *poin, void *poin2) { Base *base = poin; - Object *ob = base->object; + char *propname = poin2; + outliner_object_set_flag_recursive_cb(C, base, NULL, propname); +} - const bool is_visible = ((base->flag & BASE_HIDDEN) == 0) && - ((ob->restrictflag & OB_RESTRICT_VIEW) == 0); - return !is_visible; +/** Create either a RNA_LayerCollection or a RNA_Collection pointer. */ +static void outliner_layer_or_collection_pointer_create(Scene *scene, + LayerCollection *layer_collection, + Collection *collection, + PointerRNA *ptr) +{ + if (collection) { + RNA_id_pointer_create(&collection->id, ptr); + } + else { + RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, ptr); + } } -static void hidebutton_base_flag_cb(bContext *C, void *poin, void *poin2) +/** Create either a RNA_ObjectBase or a RNA_Object pointer. */ +static void outliner_base_or_object_pointer_create(ViewLayer *view_layer, + Collection *collection, + Object *ob, + PointerRNA *ptr) { - wmWindow *win = CTX_wm_window(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = poin; - Base *base = poin2; - Object *ob = base->object; - bool do_disable = (CTX_wm_window(C)->eventstate->alt != 0); - bool do_isolate = (win->eventstate->ctrl != 0) && !do_disable; - bool extend = (win->eventstate->shift != 0); - bool depsgraph_changed = false; - const bool is_linked = ID_IS_LINKED(ob); + if (collection) { + RNA_id_pointer_create(&ob->id, ptr); + } + else { + Base *base = BKE_view_layer_base_find(view_layer, ob); + RNA_pointer_create(&base->object->id, &RNA_ObjectBase, base, ptr); + } +} - if (do_disable) { - if (!is_linked) { - ob->restrictflag |= OB_RESTRICT_VIEW; - depsgraph_changed = true; - } +/* Note: Collection is only valid when we want to change the collection data, otherwise we get it + * from layer collection. Layer collection is valid whenever we are looking at a view layer. */ +static void outliner_collection_set_flag_recursive(Scene *scene, + ViewLayer *view_layer, + LayerCollection *layer_collection, + Collection *collection, + PropertyRNA *layer_or_collection_prop, + PropertyRNA *base_or_object_prop, + const bool value) +{ + if (layer_collection && layer_collection->flag & LAYER_COLLECTION_EXCLUDE) { + return; } - else if (do_isolate) { - depsgraph_changed = (!is_linked) && ((ob->restrictflag & OB_RESTRICT_VIEW) != 0); + PointerRNA ptr; + outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr); + RNA_property_boolean_set(&ptr, layer_or_collection_prop, value); - if (!extend) { - /* Make only one base visible. */ - for (Base *other = view_layer->object_bases.first; other; other = other->next) { - other->flag |= BASE_HIDDEN; - } + /* Set the same flag for the nested objects as well. */ + if (base_or_object_prop) { + /* Note: We can't use BKE_collection_object_cache_get() + * otherwise we would not take collection exclusion into account. */ + for (CollectionObject *cob = layer_collection->collection->gobject.first; cob; + cob = cob->next) { - base->flag &= ~BASE_HIDDEN; - } - else { - /* Toggle visibility of one base. */ - base->flag ^= BASE_HIDDEN; - } + outliner_base_or_object_pointer_create(view_layer, collection, cob->ob, &ptr); + RNA_property_boolean_set(&ptr, base_or_object_prop, value); - if (!is_linked) { - ob->restrictflag &= ~OB_RESTRICT_VIEW; + if (collection) { + DEG_id_tag_update(&cob->ob->id, ID_RECALC_COPY_ON_WRITE); + } } } - else if (ob->restrictflag & OB_RESTRICT_VIEW) { - if (!is_linked) { - ob->restrictflag &= ~OB_RESTRICT_VIEW; - base->flag &= ~BASE_HIDDEN; + + /* Keep going recursively. */ + ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children); + for (Link *link = lb->first; link; link = link->next) { + LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL; + Collection *collection_iter = layer_collection ? + (collection ? layer_collection_iter->collection : NULL) : + ((CollectionChild *)link)->collection; + outliner_collection_set_flag_recursive(scene, + view_layer, + layer_collection_iter, + collection_iter, + layer_or_collection_prop, + base_or_object_prop, + value); + } + + if (collection) { + DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); + } +} + +/** Check if collection is already isolated. + * + * A collection is isolated if all its parents and children are "visible". + * All the other collections must be "invisible". + * + * Note: We could/should boost performance by iterating over the tree twice. + * First tagging all the children/parent collections, then getting their values and comparing. + * To run BKE_collection_has_collection() so many times is silly and slow. + */ +static bool outliner_collection_is_isolated(Scene *scene, + const LayerCollection *layer_collection_cmp, + const Collection *collection_cmp, + const bool value_cmp, + const PropertyRNA *layer_or_collection_prop, + LayerCollection *layer_collection, + Collection *collection) +{ + PointerRNA ptr; + outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr); + const bool value = RNA_property_boolean_get(&ptr, (PropertyRNA *)layer_or_collection_prop); + Collection *collection_ensure = collection ? collection : layer_collection->collection; + const Collection *collection_ensure_cmp = collection_cmp ? collection_cmp : + layer_collection_cmp->collection; + + if (collection_ensure->flag & COLLECTION_IS_MASTER) { + } + else if (collection_ensure == collection_ensure_cmp) { + } + else if (BKE_collection_has_collection(collection_ensure, (Collection *)collection_ensure_cmp) || + BKE_collection_has_collection((Collection *)collection_ensure_cmp, collection_ensure)) { + /* This collection is either a parent or a child of the collection. + * We expect it to be set "visble" already. */ + if (value != value_cmp) { + return false; } - depsgraph_changed = true; } else { - base->flag ^= BASE_HIDDEN; + /* This collection is neither a parent nor a child of the collection. + * We expect it to be "invisble". */ + if (value == value_cmp) { + return false; + } } - if (depsgraph_changed) { - BKE_main_collection_sync_remap(bmain); - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_OBJECT | ND_DRAW, &ob->id); + /* Keep going recursively. */ + ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children); + for (Link *link = lb->first; link; link = link->next) { + LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL; + Collection *collection_iter = layer_collection ? + (collection ? layer_collection_iter->collection : NULL) : + ((CollectionChild *)link)->collection; + if (layer_collection_iter && layer_collection_iter->flag & LAYER_COLLECTION_EXCLUDE) { + continue; + } + if (!outliner_collection_is_isolated(scene, + layer_collection_cmp, + collection_cmp, + value_cmp, + layer_or_collection_prop, + layer_collection_iter, + collection_iter)) { + return false; + } } - if (!do_disable) { - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } + return true; } -static int layer_collection_pushed_state_cb(bContext *UNUSED(C), void *poin) +static void outliner_collection_isolate_flag(Scene *scene, + ViewLayer *view_layer, + LayerCollection *layer_collection, + Collection *collection, + PropertyRNA *layer_or_collection_prop, + const char *propname, + const bool value) { - LayerCollection *lc = poin; - Collection *collection = lc->collection; + PointerRNA ptr; + const bool is_hide = strstr(propname, "hide_") != NULL; + + LayerCollection *top_layer_collection = layer_collection ? view_layer->layer_collections.first : + NULL; + Collection *top_collection = collection ? scene->master_collection : NULL; + + bool was_isolated = (value == is_hide); + was_isolated &= outliner_collection_is_isolated(scene, + layer_collection, + collection, + !is_hide, + layer_or_collection_prop, + top_layer_collection, + top_collection); + + if (was_isolated) { + const bool default_value = RNA_property_boolean_get_default(NULL, layer_or_collection_prop); + /* Make every collection go back to its default "visibility" state. */ + outliner_collection_set_flag_recursive(scene, + view_layer, + top_layer_collection, + top_collection, + layer_or_collection_prop, + NULL, + default_value); + return; + } + + /* Make every collection "invisible". */ + outliner_collection_set_flag_recursive(scene, + view_layer, + top_layer_collection, + top_collection, + layer_or_collection_prop, + NULL, + is_hide); + + /* Make this collection and its children collections the only "visible". */ + outliner_collection_set_flag_recursive( + scene, view_layer, layer_collection, collection, layer_or_collection_prop, NULL, !is_hide); + + /* Make this collection direct parents also "visible". */ + if (layer_collection) { + LayerCollection *lc_parent = layer_collection; + for (LayerCollection *lc_iter = top_layer_collection->layer_collections.first; lc_iter; + lc_iter = lc_iter->next) { + if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) { + lc_parent = lc_iter; + break; + } + } - const bool is_visible = ((lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) == 0) && - ((collection->flag & COLLECTION_RESTRICT_VIEW) == 0); - return !is_visible; + while (lc_parent != layer_collection) { + outliner_layer_or_collection_pointer_create( + scene, lc_parent, collection ? lc_parent->collection : NULL, &ptr); + RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide); + + for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter; + lc_iter = lc_iter->next) { + if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) { + lc_parent = lc_iter; + break; + } + } + } + } + else { + CollectionParent *parent; + Collection *child = collection; + while ((parent = child->parents.first)) { + if (parent->collection->flag & COLLECTION_IS_MASTER) { + break; + } + RNA_id_pointer_create(&parent->collection->id, &ptr); + RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide); + child = parent->collection; + } + } } -static void hidebutton_layer_collection_flag_cb(bContext *C, void *poin, void *poin2) +static void outliner_collection_set_flag_recursive_cb(bContext *C, + LayerCollection *layer_collection, + Collection *collection, + const char *propname) { Main *bmain = CTX_data_main(C); wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = poin; - LayerCollection *lc = poin2; - Collection *collection = lc->collection; - bool do_disable = (win->eventstate->alt != 0); - bool do_isolate = (win->eventstate->ctrl != 0) && !do_disable; + ViewLayer *view_layer = CTX_data_view_layer(C); + PointerRNA ptr; + + bool do_isolate = (win->eventstate->ctrl != 0); bool extend = (win->eventstate->shift != 0); - bool depsgraph_changed = false; - if (do_disable) { - if (!ID_IS_LINKED(collection)) { - collection->flag |= COLLECTION_RESTRICT_VIEW; - depsgraph_changed = true; - } + if (!ELEM(true, do_isolate, extend)) { + return; } - else if (do_isolate) { - depsgraph_changed |= BKE_layer_collection_isolate(scene, view_layer, lc, extend); + + /* Create PointerRNA and PropertyRNA for either Collection or LayerCollection. */ + ID *id = collection ? &collection->id : &scene->id; + StructRNA *struct_rna = collection ? &RNA_Collection : &RNA_LayerCollection; + void *data = collection ? (void *)collection : (void *)layer_collection; + + RNA_pointer_create(id, struct_rna, data, &ptr); + outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr); + PropertyRNA *layer_or_collection_prop = RNA_struct_type_find_property(struct_rna, propname); + const bool value = RNA_property_boolean_get(&ptr, layer_or_collection_prop); + + PropertyRNA *base_or_object_prop = NULL; + if (layer_collection != NULL) { + /* If we are toggling Layer collections we still want to change the properties of the base + * or the objects. If we have a matching property, toggle it as well, it can be NULL. */ + struct_rna = collection ? &RNA_Object : &RNA_ObjectBase; + base_or_object_prop = RNA_struct_type_find_property(struct_rna, propname); } - else { - bool make_visible = ((lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0) || - ((collection->flag & COLLECTION_RESTRICT_VIEW) != 0); - depsgraph_changed |= BKE_layer_collection_set_visible(view_layer, lc, make_visible, extend); + + if (extend) { + outliner_collection_set_flag_recursive(scene, + view_layer, + layer_collection, + collection, + layer_or_collection_prop, + base_or_object_prop, + value); } + else { + outliner_collection_isolate_flag(scene, + view_layer, + layer_collection, + collection, + layer_or_collection_prop, + propname, + value); + } + + /* We don't call RNA_property_update() due to performance, so we batch update them. */ + BKE_main_collection_sync_remap(bmain); + DEG_relations_tag_update(bmain); +} - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); +/** + * Layer collection properties called from the ViewLayer mode. + * Change the (non-excluded) collection children, and the objects nested to them all. + */ +static void view_layer__layer_collection_set_flag_recursive_cb(bContext *C, + void *poin, + void *poin2) +{ + LayerCollection *layer_collection = poin; + char *propname = poin2; + outliner_collection_set_flag_recursive_cb(C, layer_collection, NULL, propname); +} - if (depsgraph_changed) { - BKE_main_collection_sync_remap(bmain); - DEG_relations_tag_update(bmain); - } - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); +/** + * Collection properties called from the ViewLayer mode. + * Change the (non-excluded) collection children, and the objects nested to them all. + */ +static void view_layer__collection_set_flag_recursive_cb(bContext *C, void *poin, void *poin2) +{ + LayerCollection *layer_collection = poin; + char *propname = poin2; + outliner_collection_set_flag_recursive_cb( + C, layer_collection, layer_collection->collection, propname); +} + +/** + * Collection properties called from the Scenes mode. + * Change the collection children but no objects. + */ +static void scenes__collection_set_flag_recursive_cb(bContext *C, void *poin, void *poin2) +{ + Collection *collection = poin; + char *propname = poin2; + outliner_collection_set_flag_recursive_cb(C, NULL, collection, propname); } static void namebutton_cb(bContext *C, void *tsep, char *oldname) @@ -568,64 +854,197 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) } } +typedef struct RestrictProperties { + bool initialized; + + PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render; + PropertyRNA *base_hide_viewport; + PropertyRNA *collection_hide_viewport, *collection_hide_select, *collection_hide_render; + PropertyRNA *layer_collection_holdout, *layer_collection_indirect_only, + *layer_collection_hide_viewport; + PropertyRNA *modifier_show_viewport, *modifier_show_render; +} RestrictProperties; + +/* We don't care about the value of the property + * but whether the property should be active or grayed out. */ +typedef struct RestrictPropertiesActive { + bool object_hide_viewport; + bool object_hide_select; + bool object_hide_render; + bool base_hide_viewport; + bool collection_hide_viewport; + bool collection_hide_select; + bool collection_hide_render; + bool layer_collection_holdout; + bool layer_collection_indirect_only; + bool layer_collection_hide_viewport; + bool modifier_show_viewport; + bool modifier_show_render; +} RestrictPropertiesActive; + +static void outliner_restrict_properties_enable_collection_set( + PointerRNA *collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active) +{ + if (props_active->collection_hide_render) { + props_active->collection_hide_render = !RNA_property_boolean_get( + collection_ptr, props->collection_hide_render); + if (!props_active->collection_hide_render) { + props_active->layer_collection_holdout = false; + props_active->layer_collection_indirect_only = false; + props_active->object_hide_render = false; + props_active->modifier_show_render = false; + } + } + + if (props_active->collection_hide_viewport) { + props_active->collection_hide_viewport = !RNA_property_boolean_get( + collection_ptr, props->collection_hide_viewport); + if (!props_active->collection_hide_viewport) { + props_active->collection_hide_select = false; + props_active->object_hide_select = false; + props_active->layer_collection_hide_viewport = false; + props_active->object_hide_viewport = false; + props_active->base_hide_viewport = false; + props_active->modifier_show_viewport = false; + } + } + + if (props_active->collection_hide_select) { + props_active->collection_hide_select = !RNA_property_boolean_get( + collection_ptr, props->collection_hide_select); + if (!props_active->collection_hide_select) { + props_active->object_hide_select = false; + } + } +} + +static void outliner_restrict_properties_enable_layer_collection_set( + PointerRNA *layer_collection_ptr, + PointerRNA *collection_ptr, + RestrictProperties *props, + RestrictPropertiesActive *props_active) +{ + outliner_restrict_properties_enable_collection_set(collection_ptr, props, props_active); + + if (props_active->layer_collection_holdout) { + props_active->layer_collection_holdout = RNA_property_boolean_get( + layer_collection_ptr, props->layer_collection_holdout); + } + + if (props_active->layer_collection_indirect_only) { + props_active->layer_collection_indirect_only = RNA_property_boolean_get( + layer_collection_ptr, props->layer_collection_indirect_only); + } + + if (props_active->layer_collection_hide_viewport) { + props_active->layer_collection_hide_viewport = !RNA_property_boolean_get( + layer_collection_ptr, props->layer_collection_hide_viewport); + + if (!props_active->layer_collection_hide_viewport) { + props_active->base_hide_viewport = false; + props_active->collection_hide_select = false; + props_active->object_hide_select = false; + } + } +} + static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ViewLayer *view_layer, ARegion *ar, SpaceOutliner *soops, - ListBase *lb) + ListBase *lb, + RestrictPropertiesActive props_active_parent) { /* Get RNA properties (once for speed). */ - static struct RestrictProperties { - bool initialized; - - PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render; - PropertyRNA *collection_hide_viewport, *collection_hide_select, *collection_hide_render; - PropertyRNA *modifier_show_viewport, *modifier_show_render; - } props = {false}; - + static RestrictProperties props = {false}; if (!props.initialized) { props.object_hide_viewport = RNA_struct_type_find_property(&RNA_Object, "hide_viewport"); props.object_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select"); props.object_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render"); - props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select"); + props.base_hide_viewport = RNA_struct_type_find_property(&RNA_ObjectBase, "hide_viewport"); props.collection_hide_viewport = RNA_struct_type_find_property(&RNA_Collection, "hide_viewport"); + props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select"); props.collection_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render"); + props.layer_collection_holdout = RNA_struct_type_find_property(&RNA_LayerCollection, + "holdout"); + props.layer_collection_indirect_only = RNA_struct_type_find_property(&RNA_LayerCollection, + "indirect_only"); + props.layer_collection_hide_viewport = RNA_struct_type_find_property(&RNA_LayerCollection, + "hide_viewport"); props.modifier_show_viewport = RNA_struct_type_find_property(&RNA_Modifier, "show_viewport"); props.modifier_show_render = RNA_struct_type_find_property(&RNA_Modifier, "show_render"); props.initialized = true; } + struct { + int select; + int hide; + int viewport; + int render; + int indirect_only; + int holdout; + } restrict_offsets = {0}; + int restrict_column_offset = 0; + + /* This will determine the order of drawing from RIGHT to LEFT. */ + if (soops->outlinevis == SO_VIEW_LAYER) { + if (soops->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) { + restrict_offsets.indirect_only = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + if (soops->show_restrict_flags & SO_RESTRICT_HOLDOUT) { + restrict_offsets.holdout = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + } + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + restrict_offsets.render = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + restrict_offsets.viewport = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + if (soops->show_restrict_flags & SO_RESTRICT_HIDE) { + restrict_offsets.hide = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + restrict_offsets.select = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + BLI_assert((restrict_column_offset * UI_UNIT_X + V2D_SCROLL_WIDTH) == + outliner_restrict_columns_width(soops)); + /* Create buttons. */ uiBut *bt; for (TreeElement *te = lb->first; te; te = te->next) { TreeStoreElem *tselem = TREESTORE(te); + RestrictPropertiesActive props_active = props_active_parent; + if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) { if (tselem->type == TSE_R_LAYER && (soops->outlinevis == SO_SCENES)) { - /* View layer render toggle. */ - ViewLayer *layer = te->directdata; + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + /* View layer render toggle. */ + ViewLayer *layer = te->directdata; - bt = uiDefIconButBitS(block, - UI_BTYPE_ICON_TOGGLE_N, - VIEW_LAYER_RENDER, - 0, - ICON_RESTRICT_RENDER_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &layer->flag, - 0, - 0, - 0, - 0, - TIP_("Use view layer for rendering")); - UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + bt = uiDefIconButBitS(block, + UI_BTYPE_ICON_TOGGLE_N, + VIEW_LAYER_RENDER, + 0, + ICON_RESTRICT_RENDER_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.render), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &layer->flag, + 0, + 0, + 0, + 0, + TIP_("Use view layer for rendering")); + UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } } else if ((tselem->type == 0 && te->idcode == ID_OB) && (te->flag & TE_CHILD_NOT_IN_COLLECTION)) { @@ -634,40 +1053,71 @@ static void outliner_draw_restrictbuts(uiBlock *block, else if (tselem->type == 0 && te->idcode == ID_OB) { PointerRNA ptr; Object *ob = (Object *)tselem->id; - RNA_pointer_create(&ob->id, &RNA_Object, ob, &ptr); - Base *base = BKE_view_layer_base_find(view_layer, ob); - - if (base) { - int icon = ICON_RESTRICT_VIEW_ON; - if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0) { - icon = (base->flag & BASE_HIDDEN) != 0 ? ICON_HIDE_ON : ICON_HIDE_OFF; + RNA_id_pointer_create(&ob->id, &ptr); + + if (soops->show_restrict_flags & SO_RESTRICT_HIDE) { + Base *base = (te->directdata) ? (Base *)te->directdata : + BKE_view_layer_base_find(view_layer, ob); + if (base) { + PointerRNA base_ptr; + RNA_pointer_create(&ob->id, &RNA_ObjectBase, base, &base_ptr); + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.hide), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &base_ptr, + props.base_hide_viewport, + -1, + 0, + 0, + 0, + 0, + TIP_("Temporarly hide in viewport\n" + "* Shift to set children")); + UI_but_func_set( + bt, outliner__base_set_flag_recursive_cb, base, (void *)"hide_viewport"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.base_hide_viewport) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } } - bt = uiDefIconBut(block, - UI_BTYPE_ICON_TOGGLE, - 0, - icon, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Hide object in viewport\n" - "* Alt to disable for all viewports\n" - "* Ctrl to isolate visibility")); - UI_but_func_set(bt, hidebutton_base_flag_cb, view_layer, base); - UI_but_func_pushed_state_set(bt, base_pushed_state_cb, base); + } + + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.select), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.object_hide_select, + -1, + 0, + 0, + -1, + -1, + TIP_("Disable selection in viewport\n" + "* Shift to set children")); + UI_but_func_set(bt, outliner__object_set_flag_recursive_cb, ob, (char *)"hide_select"); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.object_hide_select) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } } - else { + + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), te->ys, UI_UNIT_X, UI_UNIT_Y, @@ -678,256 +1128,352 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, -1, -1, + TIP_("Globally disable in viewports\n" + "* Shift to set children")); + UI_but_func_set(bt, outliner__object_set_flag_recursive_cb, ob, (void *)"hide_viewport"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.object_hide_viewport) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.render), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.object_hide_render, + -1, + 0, + 0, + -1, + -1, + TIP_("Globally disable in renders\n" + "* Shift to set children")); + UI_but_func_set(bt, outliner__object_set_flag_recursive_cb, ob, (char *)"hide_render"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.object_hide_render) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + } + else if (tselem->type == TSE_MODIFIER) { + ModifierData *md = (ModifierData *)te->directdata; + + PointerRNA ptr; + RNA_pointer_create(tselem->id, &RNA_Modifier, md, &ptr); + + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.modifier_show_viewport, + -1, + 0, + 0, + -1, + -1, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.modifier_show_viewport) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.render), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.modifier_show_render, + -1, + 0, + 0, + -1, + -1, NULL); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.modifier_show_render) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } } + } + else if (tselem->type == TSE_POSE_CHANNEL) { + bPoseChannel *pchan = (bPoseChannel *)te->directdata; + Bone *bone = pchan->bone; + Object *ob = (Object *)tselem->id; - bt = uiDefIconButR_prop(block, + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, + BONE_HIDDEN_P, 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + ICON_HIDE_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, - props.object_hide_select, - -1, + &(bone->flag), + 0, 0, 0, - -1, - -1, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + 0, + TIP_("Restrict visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } - bt = uiDefIconButR_prop(block, + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, + BONE_UNSELECTABLE, 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.select), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, - props.object_hide_render, - -1, + &(bone->flag), + 0, + 0, 0, 0, - -1, - -1, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + TIP_("Restrict selection in the 3D View")); + UI_but_func_set(bt, restrictbutton_bone_select_cb, ob->data, bone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } } - else if (tselem->type == TSE_MODIFIER) { - ModifierData *md = (ModifierData *)te->directdata; - - PointerRNA ptr; - RNA_pointer_create(tselem->id, &RNA_Modifier, md, &ptr); + else if (tselem->type == TSE_EBONE) { + EditBone *ebone = (EditBone *)te->directdata; - bt = uiDefIconButR_prop(block, + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, + BONE_HIDDEN_A, 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + ICON_RESTRICT_VIEW_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, - props.modifier_show_viewport, - -1, + &(ebone->flag), + 0, + 0, 0, 0, - -1, - -1, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + TIP_("Restrict visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_ebone_visibility_cb, NULL, ebone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } - bt = uiDefIconButR_prop(block, + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, + BONE_UNSELECTABLE, 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.select), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, - props.modifier_show_render, - -1, + &(ebone->flag), 0, 0, - -1, - -1, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - else if (tselem->type == TSE_POSE_CHANNEL) { - bPoseChannel *pchan = (bPoseChannel *)te->directdata; - Bone *bone = pchan->bone; - Object *ob = (Object *)tselem->id; - - bt = uiDefIconButBitI(block, - UI_BTYPE_ICON_TOGGLE, - BONE_HIDDEN_P, - 0, - ICON_HIDE_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &(bone->flag), - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - - bt = uiDefIconButBitI(block, - UI_BTYPE_ICON_TOGGLE, - BONE_UNSELECTABLE, - 0, - ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &(bone->flag), - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow selection in the 3D View")); - UI_but_func_set(bt, restrictbutton_bone_select_cb, ob->data, bone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - } - else if (tselem->type == TSE_EBONE) { - EditBone *ebone = (EditBone *)te->directdata; - - bt = uiDefIconButBitI(block, - UI_BTYPE_ICON_TOGGLE, - BONE_HIDDEN_A, - 0, - ICON_RESTRICT_VIEW_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &(ebone->flag), - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_ebone_visibility_cb, NULL, ebone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - - bt = uiDefIconButBitI(block, - UI_BTYPE_ICON_TOGGLE, - BONE_UNSELECTABLE, - 0, - ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &(ebone->flag), - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow selection in the 3D View")); - UI_but_func_set(bt, restrictbutton_ebone_select_cb, NULL, ebone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + 0, + 0, + TIP_("Restrict selection in the 3D View")); + UI_but_func_set(bt, restrictbutton_ebone_select_cb, NULL, ebone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } } else if (tselem->type == TSE_GP_LAYER) { ID *id = tselem->id; bGPDlayer *gpl = (bGPDlayer *)te->directdata; - bt = uiDefIconButBitS(block, - UI_BTYPE_ICON_TOGGLE, - GP_LAYER_HIDE, - 0, - ICON_HIDE_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &gpl->flag, - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - - bt = uiDefIconButBitS( - block, - UI_BTYPE_ICON_TOGGLE, - GP_LAYER_LOCKED, - 0, - ICON_UNLOCKED, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &gpl->flag, - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow editing of strokes and keyframes in this layer")); - UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + bt = uiDefIconButBitS(block, + UI_BTYPE_ICON_TOGGLE, + GP_LAYER_HIDE, + 0, + ICON_HIDE_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &gpl->flag, + 0, + 0, + 0, + 0, + TIP_("Restrict visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } + + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + bt = uiDefIconButBitS(block, + UI_BTYPE_ICON_TOGGLE, + GP_LAYER_LOCKED, + 0, + ICON_UNLOCKED, + (int)(ar->v2d.cur.xmax - restrict_offsets.select), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &gpl->flag, + 0, + 0, + 0, + 0, + TIP_("Restrict editing of strokes and keyframes in this layer")); + UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } } else if (outliner_is_collection_tree_element(te)) { - LayerCollection *lc = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata : NULL; + LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? + te->directdata : + NULL; Collection *collection = outliner_collection_from_tree_element(te); - - if ((!lc || !(lc->flag & LAYER_COLLECTION_EXCLUDE)) && + if ((!layer_collection || !(layer_collection->flag & LAYER_COLLECTION_EXCLUDE)) && !(collection->flag & COLLECTION_IS_MASTER)) { + PointerRNA collection_ptr; + PointerRNA layer_collection_ptr; RNA_id_pointer_create(&collection->id, &collection_ptr); + if (layer_collection != NULL) { + RNA_pointer_create( + &scene->id, &RNA_LayerCollection, layer_collection, &layer_collection_ptr); + } - if (lc != NULL) { - int icon = ICON_RESTRICT_VIEW_ON; - if ((collection->flag & COLLECTION_RESTRICT_VIEW) == 0) { - icon = (lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0 ? ICON_HIDE_ON : - ICON_HIDE_OFF; - } - bt = uiDefIconBut(block, - UI_BTYPE_ICON_TOGGLE, - 0, - icon, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Hide collection in viewport\n" - "* Alt to disable for all viewports\n" - "* Ctrl to isolate visibility\n" - "* Shift to hide inside objects and collections")); - UI_but_func_set(bt, hidebutton_layer_collection_flag_cb, view_layer, lc); - UI_but_func_pushed_state_set(bt, layer_collection_pushed_state_cb, lc); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + /* Update the restriction column values for the collection children. */ + if (layer_collection) { + outliner_restrict_properties_enable_layer_collection_set( + &layer_collection_ptr, &collection_ptr, &props, &props_active); } else { + outliner_restrict_properties_enable_collection_set( + &collection_ptr, &props, &props_active); + } + + if (layer_collection != NULL) { + if (soops->show_restrict_flags & SO_RESTRICT_HIDE) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.hide), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &layer_collection_ptr, + props.layer_collection_hide_viewport, + -1, + 0, + 0, + 0, + 0, + TIP_("Temporarily hide in viewport\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections and objects")); + UI_but_func_set(bt, + view_layer__layer_collection_set_flag_recursive_cb, + layer_collection, + (char *)"hide_viewport"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.layer_collection_hide_viewport) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + + if (soops->show_restrict_flags & SO_RESTRICT_HOLDOUT) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.holdout), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &layer_collection_ptr, + props.layer_collection_holdout, + -1, + 0, + 0, + 0, + 0, + TIP_("Mask out objects in collection from view layer\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections")); + UI_but_func_set(bt, + view_layer__layer_collection_set_flag_recursive_cb, + layer_collection, + (char *)"holdout"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.layer_collection_holdout) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + + if (soops->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) { + bt = uiDefIconButR_prop( + block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.indirect_only), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &layer_collection_ptr, + props.layer_collection_indirect_only, + -1, + 0, + 0, + 0, + 0, + TIP_("Objects in collection only contribute indirectly (through shadows and " + "reflections) in the view layer\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections")); + UI_but_func_set(bt, + view_layer__layer_collection_set_flag_recursive_cb, + layer_collection, + (char *)"indirect_only"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.layer_collection_indirect_only) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + } + + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), te->ys, UI_UNIT_X, UI_UNIT_Y, @@ -938,51 +1484,102 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, 0, - NULL); + TIP_("Globally disable in viewports\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections and objects")); + if (layer_collection != NULL) { + UI_but_func_set(bt, + view_layer__collection_set_flag_recursive_cb, + layer_collection, + (char *)"hide_viewport"); + } + else { + UI_but_func_set(bt, + scenes__collection_set_flag_recursive_cb, + collection, + (char *)"hide_viewport"); + } UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.collection_hide_viewport) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } } - bt = uiDefIconButR_prop(block, - UI_BTYPE_ICON_TOGGLE, - 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &collection_ptr, - props.collection_hide_render, - -1, - 0, - 0, - 0, - 0, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.render), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &collection_ptr, + props.collection_hide_render, + -1, + 0, + 0, + 0, + 0, + TIP_("Globally disable in renders\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections and objects")); + if (layer_collection != NULL) { + UI_but_func_set(bt, + view_layer__collection_set_flag_recursive_cb, + layer_collection, + (char *)"hide_render"); + } + else { + UI_but_func_set( + bt, scenes__collection_set_flag_recursive_cb, collection, (char *)"hide_render"); + } + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.collection_hide_render) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } - bt = uiDefIconButR_prop(block, - UI_BTYPE_ICON_TOGGLE, - 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &collection_ptr, - props.collection_hide_select, - -1, - 0, - 0, - 0, - 0, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.select), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &collection_ptr, + props.collection_hide_select, + -1, + 0, + 0, + 0, + 0, + TIP_("Disable selection in viewport\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections and objects")); + if (layer_collection != NULL) { + UI_but_func_set(bt, + view_layer__collection_set_flag_recursive_cb, + layer_collection, + (char *)"hide_select"); + } + else { + UI_but_func_set( + bt, scenes__collection_set_flag_recursive_cb, collection, (char *)"hide_select"); + } + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.collection_hide_select) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } } } } if (TSELEM_OPEN(tselem, soops)) { - outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &te->subtree); + outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &te->subtree, props_active); } } } @@ -1005,6 +1602,23 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOutliner *s but_flag |= UI_BUT_DISABLED; } + BLI_str_format_int_grouped(buf, id->us); + bt = uiDefBut(block, + UI_BTYPE_BUT, + 1, + buf, + (int)(ar->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + TIP_("Number of users of this data-block")); + UI_but_flag_enable(bt, but_flag); + if (id->flag & LIB_FAKEUSER) { icon = ICON_FILE_TICK; tip = TIP_("Data-block will be retained using a fake user"); @@ -1018,7 +1632,7 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOutliner *s LIB_FAKEUSER, 1, icon, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + (int)(ar->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS), te->ys, UI_UNIT_X, UI_UNIT_Y, @@ -1031,29 +1645,12 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOutliner *s UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL); UI_but_flag_enable(bt, but_flag); - BLI_str_format_int_grouped(buf, id->us); - bt = uiDefBut(block, - UI_BTYPE_BUT, - 1, - buf, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - TIP_("Number of users of this data-block")); - UI_but_flag_enable(bt, but_flag); - bt = uiDefButBitS(block, UI_BTYPE_ICON_TOGGLE, LIB_FAKEUSER, 1, (id->flag & LIB_FAKEUSER) ? "F" : " ", - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + (int)(ar->v2d.cur.xmax - OL_TOG_USER_BUTS_FAKEUSER), te->ys, UI_UNIT_X, UI_UNIT_Y, @@ -1179,8 +1776,13 @@ static void outliner_draw_rnabuts( } } -static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te) +static void outliner_buttons(const bContext *C, + uiBlock *block, + ARegion *ar, + const float restrict_column_width, + TreeElement *te) { + SpaceOutliner *soops = CTX_wm_space_outliner(C); uiBut *bt; TreeStoreElem *tselem; int spx, dx, len; @@ -1206,7 +1808,11 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Tre } spx = te->xs + 1.8f * UI_UNIT_X; - dx = ar->v2d.cur.xmax - (spx + 3.2f * UI_UNIT_X); + if ((tselem->type == TSE_LAYER_COLLECTION) && + (soops->show_restrict_flags & SO_RESTRICT_ENABLE)) { + spx += UI_UNIT_X; + } + dx = ar->v2d.cur.xmax - (spx + restrict_column_width + 0.2f * UI_UNIT_X); bt = uiDefBut(block, UI_BTYPE_TEXT, @@ -1778,6 +2384,60 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) return data; } +static void tselem_draw_layer_collection_enable_icon( + Scene *scene, uiBlock *block, int xmax, float x, float y, TreeElement *te, float alpha) +{ + /* Get RNA property (once for speed). */ + static PropertyRNA *exclude_prop = NULL; + if (exclude_prop == NULL) { + exclude_prop = RNA_struct_type_find_property(&RNA_LayerCollection, "exclude"); + } + + if (x >= xmax) { + /* Placement of icons, copied from interface_widgets.c. */ + float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT; + x += 2.0f * aspect; + y += 2.0f * aspect; + + /* restrict column clip... it has been coded by simply overdrawing, + * doesn't work for buttons */ + char color[4]; + int icon = RNA_property_ui_icon(exclude_prop); + if (UI_icon_get_theme_color(icon, (uchar *)color)) { + UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, alpha, 0.0f, color, true); + } + else { + UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, alpha, 0.0f, NULL, false); + } + } + else { + LayerCollection *layer_collection = te->directdata; + PointerRNA layer_collection_ptr; + RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, &layer_collection_ptr); + + char emboss = UI_block_emboss_get(block); + UI_block_emboss_set(block, UI_EMBOSS_NONE); + uiBut *bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + x, + y, + UI_UNIT_X, + UI_UNIT_Y, + &layer_collection_ptr, + exclude_prop, + -1, + 0, + 0, + 0, + 0, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_block_emboss_set(block, emboss); + } +} + static void tselem_draw_icon(uiBlock *block, int xmax, float x, @@ -1801,7 +2461,13 @@ static void tselem_draw_icon(uiBlock *block, /* restrict column clip... it has been coded by simply overdrawing, * doesn't work for buttons */ - UI_icon_draw_alpha(x, y, data.icon, alpha); + char color[4]; + if (UI_icon_get_theme_color(data.icon, (uchar *)color)) { + UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true); + } + else { + UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, NULL, false); + } } else { uiDefIconBut(block, @@ -1868,6 +2534,17 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle, GPU_blend(true); /* Roundbox and text drawing disables. */ } +static void outliner_icon_background_colors(float icon_color[4], float icon_border[4]) +{ + float text[4]; + UI_GetThemeColor4fv(TH_TEXT, text); + + copy_v3_v3(icon_color, text); + icon_color[3] = 0.4f; + copy_v3_v3(icon_border, text); + icon_border[3] = 0.2f; +} + static void outliner_draw_iconrow_doit(uiBlock *block, TreeElement *te, const uiFontStyle *fstyle, @@ -1882,23 +2559,34 @@ static void outliner_draw_iconrow_doit(uiBlock *block, if (active != OL_DRAWSEL_NONE) { float ufac = UI_UNIT_X / 20.0f; - float color[4] = {1.0f, 1.0f, 1.0f, 0.2f}; - + float icon_color[4], icon_border[4]; + outliner_icon_background_colors(icon_color, icon_border); + icon_color[3] *= alpha_fac; + if (active == OL_DRAWSEL_ACTIVE) { + UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_color); + icon_border[3] = 0.3f; + } UI_draw_roundbox_corner_set(UI_CNR_ALL); - color[3] *= alpha_fac; UI_draw_roundbox_aa(true, - (float)*offsx + 1.0f * ufac, - (float)ys + 1.0f * ufac, - (float)*offsx + UI_UNIT_X - 1.0f * ufac, + (float)*offsx, + (float)ys + ufac, + (float)*offsx + UI_UNIT_X, + (float)ys + UI_UNIT_Y - ufac, + (float)UI_UNIT_Y / 4.0f, + icon_color); + /* border around it */ + UI_draw_roundbox_aa(false, + (float)*offsx, + (float)ys + ufac, + (float)*offsx + UI_UNIT_X, (float)ys + UI_UNIT_Y - ufac, - (float)UI_UNIT_Y / 2.0f - ufac, - color); + (float)UI_UNIT_Y / 4.0f, + icon_border); GPU_blend(true); /* Roundbox disables. */ } - /* No inlined icon should be clickable. */ - tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.8f * alpha_fac, false); + tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, alpha_fac, false); te->xs = *offsx; te->ys = ys; te->xend = (short)*offsx + UI_UNIT_X; @@ -1952,7 +2640,7 @@ static void outliner_draw_iconrow(bContext *C, float alpha_fac, MergedIconRow *merged) { - eOLDrawState active; + eOLDrawState active = OL_DRAWSEL_NONE; const Object *obact = OBACT(view_layer); for (TreeElement *te = lb->first; te; te = te->next) { @@ -1972,7 +2660,7 @@ static void outliner_draw_iconrow(bContext *C, OL_DRAWSEL_NONE; } else if (is_object_data_in_editmode(tselem->id, obact)) { - active = OL_DRAWSEL_NORMAL; + active = OL_DRAWSEL_ACTIVE; } else { active = tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false); @@ -2068,21 +2756,23 @@ static void outliner_draw_tree_element(bContext *C, bool draw_grayed_out, int startx, int *starty, + const float restrict_column_width, TreeElement **te_edit) { - TreeStoreElem *tselem; + TreeStoreElem *tselem = TREESTORE(te); float ufac = UI_UNIT_X / 20.0f; int offsx = 0; eOLDrawState active = OL_DRAWSEL_NONE; - float color[4]; - tselem = TREESTORE(te); + unsigned char text_color[4]; + UI_GetThemeColor4ubv(TH_TEXT, text_color); + float icon_bgcolor[4], icon_border[4]; + outliner_icon_background_colors(icon_bgcolor, icon_border); if (*starty + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && *starty <= ar->v2d.cur.ymax) { const float alpha_fac = ((te->flag & TE_DISABLED) || (te->flag & TE_CHILD_NOT_IN_COLLECTION) || draw_grayed_out) ? 0.5f : 1.0f; - const float alpha = 0.5f * alpha_fac; int xmax = ar->v2d.cur.xmax; if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) { @@ -2090,8 +2780,8 @@ static void outliner_draw_tree_element(bContext *C, } /* icons can be ui buts, we don't want it to overlap with restrict */ - if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) { - xmax -= OL_TOGW + UI_UNIT_X; + if (restrict_column_width > 0) { + xmax -= restrict_column_width + UI_UNIT_X; } GPU_blend(true); @@ -2101,7 +2791,8 @@ static void outliner_draw_tree_element(bContext *C, const Object *obact = OBACT(view_layer); if (te->idcode == ID_SCE) { if (tselem->id == (ID *)scene) { - rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); + /* active scene */ + icon_bgcolor[3] = 0.2f; active = OL_DRAWSEL_ACTIVE; } } @@ -2111,35 +2802,33 @@ static void outliner_draw_tree_element(bContext *C, BKE_view_layer_base_find(view_layer, ob); const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0); - if (ob == obact || is_selected) { - uchar col[4] = {0, 0, 0, 0}; - - /* outliner active ob: always white text, circle color now similar to view3d */ - + if (ob == obact) { active = OL_DRAWSEL_ACTIVE; - if (ob == obact) { - if (is_selected) { - UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col); - col[3] = alpha; - } + } - active = OL_DRAWSEL_NORMAL; + if (is_selected) { + if (ob == obact) { + /* active selected object */ + UI_GetThemeColor3ubv(TH_ACTIVE_OBJECT, text_color); + text_color[3] = 255; } - else if (is_selected) { - UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col); - col[3] = alpha; + else { + /* other selected objects */ + UI_GetThemeColor3ubv(TH_SELECTED_OBJECT, text_color); + text_color[3] = 255; } - rgba_float_args_set( - color, (float)col[0] / 255, (float)col[1] / 255, (float)col[2] / 255, alpha); } } else if (is_object_data_in_editmode(tselem->id, obact)) { - rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); + /* objects being edited */ + UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_bgcolor); + icon_border[3] = 0.3f; active = OL_DRAWSEL_ACTIVE; } else { if (tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false)) { - rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); + /* active items like camera or material */ + icon_bgcolor[3] = 0.2f; active = OL_DRAWSEL_ACTIVE; } } @@ -2147,19 +2836,36 @@ static void outliner_draw_tree_element(bContext *C, else { active = tree_element_type_active( C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false); - rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); + /* active collection*/ + icon_bgcolor[3] = 0.2f; + } + + /* Checkbox to enable collections. */ + if ((tselem->type == TSE_LAYER_COLLECTION) && + (soops->show_restrict_flags & SO_RESTRICT_ENABLE)) { + tselem_draw_layer_collection_enable_icon( + scene, block, xmax, (float)startx + offsx + UI_UNIT_X, (float)*starty, te, 0.8f); + offsx += UI_UNIT_X; } /* active circle */ if (active != OL_DRAWSEL_NONE) { UI_draw_roundbox_corner_set(UI_CNR_ALL); UI_draw_roundbox_aa(true, - (float)startx + UI_UNIT_X + 1.0f * ufac, - (float)*starty + 1.0f * ufac, - (float)startx + 2.0f * UI_UNIT_X - 1.0f * ufac, - (float)*starty + UI_UNIT_Y - 1.0f * ufac, - UI_UNIT_Y / 2.0f - 1.0f * ufac, - color); + (float)startx + offsx + UI_UNIT_X, + (float)*starty + ufac, + (float)startx + offsx + 2.0f * UI_UNIT_X, + (float)*starty + UI_UNIT_Y - ufac, + UI_UNIT_Y / 4.0f, + icon_bgcolor); + /* border around it */ + UI_draw_roundbox_aa(false, + (float)startx + offsx + UI_UNIT_X, + (float)*starty + ufac, + (float)startx + offsx + 2.0f * UI_UNIT_X, + (float)*starty + UI_UNIT_Y - ufac, + UI_UNIT_Y / 4.0f, + icon_border); GPU_blend(true); /* roundbox disables it */ te->flag |= TE_ACTIVE; // for lookup in display hierarchies @@ -2190,7 +2896,6 @@ static void outliner_draw_tree_element(bContext *C, offsx += UI_UNIT_X; /* datatype icon */ - if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE))) { tselem_draw_icon( block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac, true); @@ -2232,21 +2937,12 @@ static void outliner_draw_tree_element(bContext *C, /* name */ if ((tselem->flag & TSE_TEXTBUT) == 0) { - unsigned char text_col[4]; - - if (active == OL_DRAWSEL_NORMAL) { - UI_GetThemeColor4ubv(TH_TEXT_HI, text_col); - } - else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { - UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_col); - text_col[3] = 255; - } - else { - UI_GetThemeColor4ubv(TH_TEXT, text_col); + if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_color); + text_color[3] = 255; } - text_col[3] *= alpha_fac; - - UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_col); + text_color[3] *= alpha_fac; + UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_color); } offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name)); @@ -2306,6 +3002,7 @@ static void outliner_draw_tree_element(bContext *C, draw_childs_grayed_out, startx + UI_UNIT_X, starty, + restrict_column_width, te_edit); } } @@ -2513,11 +3210,15 @@ static void outliner_draw_highlights_recursive(unsigned pos, if (tselem->flag & TSE_DRAG_BEFORE) { immUniformColor4fv(col); - immRecti(pos, start_x, start_y + UI_UNIT_Y, end_x, start_y + UI_UNIT_Y); + immRecti(pos, + start_x, + start_y + UI_UNIT_Y - U.pixelsize, + end_x, + start_y + UI_UNIT_Y + U.pixelsize); } else if (tselem->flag & TSE_DRAG_AFTER) { immUniformColor4fv(col); - immRecti(pos, start_x, start_y, end_x, start_y); + immRecti(pos, start_x, start_y - U.pixelsize, end_x, start_y + U.pixelsize); } else { immUniformColor3fvAlpha(col, col[3] * 0.5f); @@ -2581,7 +3282,7 @@ static void outliner_draw_tree(bContext *C, ViewLayer *view_layer, ARegion *ar, SpaceOutliner *soops, - const bool has_restrict_icons, + const float restrict_column_width, TreeElement **te_edit) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; @@ -2603,8 +3304,8 @@ static void outliner_draw_tree(bContext *C, /* set scissor so tree elements or lines can't overlap restriction icons */ float scissor[4] = {0}; - if (has_restrict_icons) { - int mask_x = BLI_rcti_size_x(&ar->v2d.mask) - (int)OL_TOGW + 1; + if (restrict_column_width > 0.0f) { + int mask_x = BLI_rcti_size_x(&ar->v2d.mask) - (int)restrict_column_width + 1; CLAMP_MIN(mask_x, 0); GPU_scissor_get_f(scissor); @@ -2632,10 +3333,11 @@ static void outliner_draw_tree(bContext *C, (te->flag & TE_DRAGGING) != 0, startx, &starty, + restrict_column_width, te_edit); } - if (has_restrict_icons) { + if (restrict_column_width > 0.0f) { /* reset scissor */ GPU_scissor(UNPACK4(scissor)); } @@ -2652,7 +3354,10 @@ static void outliner_back(ARegion *ar) uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColorShade(TH_BACK, 6); + + float col_alternating[4]; + UI_GetThemeColor4fv(TH_ROW_ALTERNATE, col_alternating); + immUniformThemeColorBlend(TH_BACK, TH_ROW_ALTERNATE, col_alternating[3]); const float x1 = 0.0f, x2 = ar->v2d.cur.xmax; float y1 = ystart, y2; @@ -2690,7 +3395,6 @@ void draw_outliner(const bContext *C) uiBlock *block; int sizey = 0, sizex = 0, sizex_rna = 0; TreeElement *te_edit = NULL; - bool has_restrict_icons; outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always @@ -2700,6 +3404,7 @@ void draw_outliner(const bContext *C) /* extend size to allow for horizontal scrollbar */ sizey += V2D_SCROLL_HEIGHT; + const float restrict_column_width = outliner_restrict_columns_width(soops); if (soops->outlinevis == SO_DATA_API) { /* RNA has two columns: * - column 1 is (max_width + OL_RNA_COL_SPACEX) or @@ -2715,7 +3420,6 @@ void draw_outliner(const bContext *C) /* get width of data (for setting 'tot' rect, this is column 1 + column 2 + a bit extra) */ sizex = sizex_rna + OL_RNA_COL_SIZEX + 50; - has_restrict_icons = false; } else { /* width must take into account restriction columns (if visible) @@ -2724,13 +3428,8 @@ void draw_outliner(const bContext *C) // XXX should use outliner_width instead when te->xend will be set correctly... outliner_rna_width(soops, &soops->tree, &sizex, 0); - /* constant offset for restriction columns */ - // XXX this isn't that great yet... - if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) { - sizex += OL_TOGW * 3; - } - - has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS); + /* Constant offset for restriction columns */ + sizex += restrict_column_width; } /* adds vertical offset */ @@ -2748,7 +3447,7 @@ void draw_outliner(const bContext *C) outliner_back(ar); block = UI_block_begin(C, ar, __func__, UI_EMBOSS); outliner_draw_tree( - (bContext *)C, block, scene, view_layer, ar, soops, has_restrict_icons, &te_edit); + (bContext *)C, block, scene, view_layer, ar, soops, restrict_column_width, &te_edit); /* Default to no emboss for outliner UI. */ UI_block_emboss_set(block, UI_EMBOSS_NONE); @@ -2761,20 +3460,22 @@ void draw_outliner(const bContext *C) outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree); UI_block_emboss_set(block, UI_EMBOSS_NONE); } - else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { + else if (soops->outlinevis == SO_ID_ORPHANS) { /* draw user toggle columns */ outliner_draw_userbuts(block, ar, soops, &soops->tree); } - else if (has_restrict_icons) { + else if (restrict_column_width > 0.0f) { /* draw restriction columns */ - outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &soops->tree); + RestrictPropertiesActive props_active; + memset(&props_active, 1, sizeof(RestrictPropertiesActive)); + outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &soops->tree, props_active); } UI_block_emboss_set(block, UI_EMBOSS); - /* draw edit buttons if nessecery */ + /* Draw edit buttons if necessary. */ if (te_edit) { - outliner_buttons(C, block, ar, te_edit); + outliner_buttons(C, block, ar, restrict_column_width, te_edit); } UI_block_end(C, block); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index a943e972cf5..c32b2b051f8 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -88,6 +88,11 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { + /* stop highlighting if out of area */ + if (!ED_screen_area_active(C)) { + return OPERATOR_PASS_THROUGH; + } + /* Drag and drop does own highlighting. */ wmWindowManager *wm = CTX_wm_manager(C); if (wm->drags.first) { @@ -1025,8 +1030,8 @@ int common_restrict_check(bContext *C, Object *ob) Object *obedit = CTX_data_edit_object(C); if (obedit && obedit == ob) { /* found object is hidden, reset */ - if (ob->restrictflag & OB_RESTRICT_VIEW) { - ob->restrictflag &= ~OB_RESTRICT_VIEW; + if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { + ob->restrictflag &= ~OB_RESTRICT_VIEWPORT; } /* found object is unselectable, reset */ if (ob->restrictflag & OB_RESTRICT_SELECT) { diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 8211e3005c7..15489c61230 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -156,11 +156,9 @@ typedef enum { /* size constants */ #define OL_Y_OFFSET 2 -#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 3.0f + V2D_SCROLL_WIDTH) -#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 2.0f + V2D_SCROLL_WIDTH) -#define OL_TOG_RESTRICT_RENDERX (UI_UNIT_X + V2D_SCROLL_WIDTH) - -#define OL_TOGW OL_TOG_RESTRICT_SELECTX +#define OL_TOG_USER_BUTS_USERS (UI_UNIT_X * 2.0f + V2D_SCROLL_WIDTH) +#define OL_TOG_USER_BUTS_STATUS (UI_UNIT_X * 3.0f + V2D_SCROLL_WIDTH) +#define OL_TOG_USER_BUTS_FAKEUSER (UI_UNIT_X + V2D_SCROLL_WIDTH) #define OL_RNA_COLX (UI_UNIT_X * 15) #define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f) @@ -449,5 +447,6 @@ bool outliner_tree_traverse(const SpaceOutliner *soops, int filter_tselem_flag, TreeTraversalFunc func, void *customdata); +float outliner_restrict_columns_width(const struct SpaceOutliner *soops); #endif /* __OUTLINER_INTERN_H__ */ diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 995f41382cd..ae17158829c 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -450,32 +450,6 @@ static eOLDrawState tree_element_active_material(bContext *C, return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_light(bContext *UNUSED(C), - Scene *UNUSED(scene), - ViewLayer *view_layer, - SpaceOutliner *soops, - TreeElement *te, - const eOLSetState set) -{ - Object *ob; - - /* we search for the object parent */ - ob = (Object *)outliner_search_back(soops, te, ID_OB); - if (ob == NULL || ob != OBACT(view_layer)) { - /* just paranoia */ - return OL_DRAWSEL_NONE; - } - - if (set != OL_SETSEL_NONE) { - // XXX extern_set_butspace(F5KEY, 0); - } - else { - return OL_DRAWSEL_NORMAL; - } - - return OL_DRAWSEL_NONE; -} - static eOLDrawState tree_element_active_camera(bContext *UNUSED(C), Scene *scene, ViewLayer *UNUSED(sl), @@ -1041,8 +1015,6 @@ eOLDrawState tree_element_active(bContext *C, return tree_element_active_material(C, scene, view_layer, soops, te, set); case ID_WO: return tree_element_active_world(C, scene, view_layer, soops, te, set); - case ID_LA: - return tree_element_active_light(C, scene, view_layer, soops, te, set); case ID_TXT: return tree_element_active_text(C, scene, view_layer, soops, te, set); case ID_CA: @@ -1271,8 +1243,7 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops, const ARegion *ar, float view_co_x) { - return ((soops->outlinevis != SO_DATA_API) && !(soops->flag & SO_HIDE_RESTRICTCOLS) && - (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)); + return (view_co_x > ar->v2d.cur.xmax - outliner_restrict_columns_width(soops)); } /** diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 4e3fd6037bb..80424f021e2 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -302,6 +302,9 @@ static void outliner_add_scene_contents(SpaceOutliner *soops, tenlay->directdata = view_layer; } + /* World */ + outliner_add_element(soops, lb, sce->world, te, 0, 0); + /* Collections */ ten = outliner_add_element(soops, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0); ten->name = IFACE_("Scene Collection"); @@ -1370,6 +1373,12 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops, const bool show_objects) { for (LayerCollection *lc = layer_collections->first; lc; lc = lc->next) { + const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0; + + if (exclude && ((soops->show_restrict_flags & SO_RESTRICT_ENABLE) == 0)) { + continue; + } + ID *id = &lc->collection->id; TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); @@ -1382,8 +1391,7 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops, tselem->flag &= ~TSE_CLOSED; } - const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0; - if (exclude || ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0)) { + if (exclude || (lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) { ten->flag |= TE_DISABLED; } diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index 03d15088380..f57dce97b38 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -31,6 +31,7 @@ #include "ED_armature.h" #include "UI_interface.h" +#include "UI_view2d.h" #include "outliner_intern.h" @@ -261,3 +262,41 @@ bool outliner_tree_traverse(const SpaceOutliner *soops, return true; } + +float outliner_restrict_columns_width(const SpaceOutliner *soops) +{ + int num_columns = 0; + + switch (soops->outlinevis) { + case SO_DATA_API: + case SO_SEQUENCE: + case SO_LIBRARIES: + return 0.0f; + case SO_ID_ORPHANS: + num_columns = 3; + break; + case SO_VIEW_LAYER: + if (soops->show_restrict_flags & SO_RESTRICT_HOLDOUT) { + num_columns++; + } + if (soops->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) { + num_columns++; + } + ATTR_FALLTHROUGH; + case SO_SCENES: + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + num_columns++; + } + if (soops->show_restrict_flags & SO_RESTRICT_HIDE) { + num_columns++; + } + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + num_columns++; + } + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + num_columns++; + } + break; + } + return (num_columns * UI_UNIT_X + V2D_SCROLL_WIDTH); +} diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index a8e3129b5b4..313e6014b88 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -302,6 +302,7 @@ static SpaceLink *outliner_new(const ScrArea *UNUSED(area), const Scene *UNUSED( soutliner = MEM_callocN(sizeof(SpaceOutliner), "initoutliner"); soutliner->spacetype = SPACE_OUTLINER; soutliner->filter_id_type = ID_GR; + soutliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE; /* header */ ar = MEM_callocN(sizeof(ARegion), "header for outliner"); @@ -383,6 +384,14 @@ static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, } } +static void outliner_deactivate(struct ScrArea *sa) +{ + /* Remove hover highlights */ + SpaceOutliner *soops = sa->spacedata.first; + outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED, false); + ED_region_tag_redraw(BKE_area_find_region_type(sa, RGN_TYPE_WINDOW)); +} + /* only called once, from space_api/spacetypes.c */ void ED_spacetype_outliner(void) { @@ -400,6 +409,7 @@ void ED_spacetype_outliner(void) st->keymap = outliner_keymap; st->dropboxes = outliner_dropboxes; st->id_remap = outliner_id_remap; + st->deactivate = outliner_deactivate; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region"); diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index b5bb79fb430..e8f18eeebc7 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -149,7 +149,7 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type) int proximity = INT_MAX; if (!ed || !ed->seqbasep) { - return 1; + return 2; } for (seq = ed->seqbasep->first; seq; seq = seq->next) { @@ -161,9 +161,9 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type) } if (tgt) { - return tgt->machine; + return tgt->machine + 1; } - return 1; + return 2; } static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, int flag, int type) @@ -173,7 +173,7 @@ static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, i int cfra = (int)CFRA; /* effect strips don't need a channel initialized from the mouse */ - if (!(flag & SEQPROP_NOCHAN)) { + if (!(flag & SEQPROP_NOCHAN) && RNA_struct_property_is_set(op->ptr, "channel") == 0) { RNA_int_set(op->ptr, "channel", sequencer_generic_invoke_xy_guess_channel(C, type)); } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 86bc315b994..fb875c8c4a4 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -60,6 +60,7 @@ #include "ED_mask.h" #include "ED_sequencer.h" #include "ED_screen.h" +#include "ED_time_scrub_ui.h" #include "ED_space_api.h" #include "BIF_glutil.h" @@ -960,7 +961,7 @@ static void draw_seq_strip(const bContext *C, x1 = seq->startdisp + handsize_clamped; x2 = seq->enddisp - handsize_clamped; - float scroller_vert_xoffs = (V2D_SCROLL_WIDTH_TEXT + SEQ_SCROLLER_TEXT_OFFSET) * pixelx; + float scroller_vert_xoffs = (V2D_SCROLL_WIDTH_HANDLES + SEQ_SCROLLER_TEXT_OFFSET) * pixelx; /* info text on the strip */ if (x1 < v2d->cur.xmin + scroller_vert_xoffs) { @@ -1120,8 +1121,7 @@ static void sequencer_display_size(Scene *scene, float r_viewrect[2]) r_viewrect[0] = (float)scene->r.xsch; r_viewrect[1] = (float)scene->r.ysch; - /* Aspect ratio seems to have no effect on output image*/ - /* r_viewrect[0] *= scene->r.xasp / scene->r.yasp; */ + r_viewrect[0] *= scene->r.xasp / scene->r.yasp; } static void sequencer_draw_gpencil(const bContext *C) @@ -1821,7 +1821,7 @@ typedef struct CacheDrawData { /* Called as a callback */ static bool draw_cache_view_cb( - void *userdata, struct Sequence *seq, int cfra, int cache_type, float UNUSED(cost)) + void *userdata, struct Sequence *seq, int nfra, int cache_type, float UNUSED(cost)) { CacheDrawData *drawdata = userdata; const bContext *C = drawdata->C; @@ -1847,8 +1847,7 @@ static bool draw_cache_view_cb( color[2] = 0.2f; stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) - v2d->cur.ymin; - ; - stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HEIGHT_TEXT); + stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HEIGHT_HANDLES); stripe_top = stripe_bot + stripe_ht; break; } @@ -1902,6 +1901,7 @@ static bool draw_cache_view_cb( } } + int cfra = seq->start + nfra; immUniformColor4f(color[0], color[1], color[2], color[3]); immRectf(pos, cfra, stripe_bot, cfra + 1, stripe_top); @@ -1922,12 +1922,16 @@ static void draw_cache_view(const bContext *C) uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - float stripe_bot, stripe_top, stripe_offs; + float stripe_bot, stripe_top; + float stripe_offs = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin; float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) - v2d->cur.ymin; + CLAMP_MAX(stripe_ht, 0.2f); + CLAMP_MIN(stripe_offs, stripe_ht / 2); + if (scene->ed->cache_flag & SEQ_CACHE_VIEW_FINAL_OUT) { - stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HEIGHT_TEXT); + stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HEIGHT_HANDLES); stripe_top = stripe_bot + stripe_ht; float bg_color[4] = {1.0f, 0.4f, 0.2f, 0.1f}; @@ -1944,10 +1948,6 @@ static void draw_cache_view(const bContext *C) continue; } - CLAMP_MAX(stripe_ht, 0.2f); - stripe_offs = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin; - CLAMP_MIN(stripe_offs, stripe_ht / 2); - stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs; stripe_top = stripe_bot + stripe_ht; @@ -2086,19 +2086,22 @@ void draw_timeline_seq(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + /* scrubbing region */ + ED_scrubbing_draw(ar, scene, !(sseq->flag & SEQ_DRAWFRAMES), true); + /* scrollers */ scrollers = UI_view2d_scrollers_calc(v2d, NULL); UI_view2d_scrollers_draw(v2d, scrollers); UI_view2d_scrollers_free(scrollers); - /* scale numbers */ - UI_view2d_draw_scale_x__discrete_frames_or_seconds( - ar, v2d, &v2d->hor, scene, !(sseq->flag & SEQ_DRAWFRAMES)); - UI_view2d_draw_scale_y__block(ar, v2d, &v2d->vert); - - /* draw current frame number-indicator on top of scrollers */ - if ((sseq->flag & SEQ_NO_DRAW_CFRANUM) == 0) { - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); + /* channel numbers */ + { + rcti rect; + BLI_rcti_init(&rect, + 0, + 15 * UI_DPI_FAC, + 15 * UI_DPI_FAC, + UI_DPI_FAC * ar->sizey - UI_SCRUBBING_MARGIN_Y); + UI_view2d_draw_scale_y__block(ar, v2d, &rect, TH_SCROLL_TEXT); } } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 94437d4871a..a3030153e6c 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1343,7 +1343,7 @@ static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNU void SEQUENCER_OT_snap(struct wmOperatorType *ot) { /* identifiers */ - ot->name = "Snap Strips to Frame"; + ot->name = "Snap Strips to Playhead"; ot->idname = "SEQUENCER_OT_snap"; ot->description = "Frame where selected strips will be snapped"; diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index e16029395bd..593dd86477a 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -108,6 +108,8 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event) UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy); + fx /= scene->r.xasp / scene->r.yasp; + fx += (float)scene->r.xsch / 2.0f; fy += (float)scene->r.ysch / 2.0f; fx *= (float)ibuf->x / (float)scene->r.xsch; diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 2b0c29a02ad..6ab44ded046 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -157,8 +157,8 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene) ar->v2d.minzoom = 0.01f; ar->v2d.maxzoom = 100.0f; - ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); - ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_SCALE_VERTICAL); + ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); + ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HANDLES); ar->v2d.keepzoom = 0; ar->v2d.keeptot = 0; ar->v2d.align = V2D_ALIGN_NO_NEG_Y; @@ -729,6 +729,7 @@ static void sequencer_buttons_region_init(wmWindowManager *wm, ARegion *ar) keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0); WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap); + UI_panel_category_active_set_default(ar, "Strip"); ED_region_panels_init(wm, ar); } @@ -816,7 +817,7 @@ void ED_spacetype_sequencer(void) art->draw = sequencer_main_region_draw; art->listener = sequencer_main_region_listener; art->message_subscribe = sequencer_main_region_message_subscribe; - art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION; + art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION; BLI_addhead(&st->regiontypes, art); @@ -832,7 +833,7 @@ void ED_spacetype_sequencer(void) /* regions: listview/buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 220; // XXX + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = sequencer_buttons_region_listener; art->init = sequencer_buttons_region_init; diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c index 243642b2e8c..c36175489b3 100644 --- a/source/blender/editors/space_text/text_autocomplete.c +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -74,7 +74,7 @@ int text_do_suggest_select(SpaceText *st, ARegion *ar) /* Count the visible lines to the cursor */ for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) { - ; + /* pass */ } if (l < 0) { return 0; @@ -101,7 +101,7 @@ int text_do_suggest_select(SpaceText *st, ARegion *ar) /* Work out which of the items is at the top of the visible list */ for (i = 0, item = first; i < *top && item->next; i++, item = item->next) { - ; + /* pass */ } /* Work out the target item index in the visible list */ @@ -111,7 +111,7 @@ int text_do_suggest_select(SpaceText *st, ARegion *ar) } for (i = tgti; i > 0 && item->next; i--, item = item->next) { - ; + /* pass */ } if (item) { texttool_suggest_select(item); diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index cdd691fe879..ac1fb4af1c2 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -1186,7 +1186,7 @@ static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc /* Set the top 'item' of the visible list */ for (i = 0, item = first; i < *top && item->next; i++, item = item->next) { - ; + /* pass */ } for (i = 0; i < SUGG_LIST_SIZE && item; i++, item = item->next) { @@ -1665,12 +1665,14 @@ void draw_text_main(SpaceText *st, ARegion *ar) immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + GPU_line_width(2.0f); + float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); - immUniform1i("colors_len", 0); /* "simple" mode */ - immUniformThemeColor(TH_GRID); /* same color as line number background */ + immUniform1i("colors_len", 0); /* "simple" mode */ + immUniformThemeColor3(TH_GRID); /* same color as line number background */ immUniform1f("dash_width", 2.0f); immUniform1f("dash_factor", 0.5f); diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 7b6e0ff8771..2593571d9a3 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -101,7 +101,7 @@ static char *buf_tabs_to_spaces(const char *in_buf, const int tab_size) } /* Allocate output before with extra space for expanded tabs. */ - const int out_size = strlen(in_buf) + num_tabs * (tab_size - 1); + const int out_size = strlen(in_buf) + num_tabs * (tab_size - 1) + 1; char *out_buf = MEM_mallocN(out_size * sizeof(char), __func__); /* Fill output buffer. */ @@ -247,7 +247,7 @@ static int text_new_exec(bContext *C, wmOperator *UNUSED(op)) if (prop) { RNA_id_pointer_create(&text->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } else if (st) { @@ -326,7 +326,7 @@ static int text_open_exec(bContext *C, wmOperator *op) if (pprop->prop) { RNA_id_pointer_create(&text->id, &idptr); - RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); + RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); RNA_property_update(C, &pprop->ptr, pprop->prop); } else if (st) { @@ -1268,7 +1268,7 @@ static int text_convert_whitespace_exec(bContext *C, wmOperator *op) for (j = 1; (j < tab_len) && (a + j < text_check_line_len) && (text_check_line[a + j] == ' '); j++) { - ; + /* pass */ } if (j == tab_len) { diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c index 8b290009a97..725a49e417e 100644 --- a/source/blender/editors/space_topbar/space_topbar.c +++ b/source/blender/editors/space_topbar/space_topbar.c @@ -213,12 +213,15 @@ static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu) { struct RecentFile *recent; uiLayout *layout = menu->layout; - uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN); + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); if (!BLI_listbase_is_empty(&G.recent_files)) { for (recent = G.recent_files.first; (recent); recent = recent->next) { const char *file = BLI_path_basename(recent->filepath); const int icon = BLO_has_bfile_extension(file) ? ICON_FILE_BLEND : ICON_FILE_BACKUP; - uiItemStringO(layout, file, icon, "WM_OT_open_mainfile", "filepath", recent->filepath); + PointerRNA ptr; + uiItemFullO(layout, "WM_OT_open_mainfile", file, icon, NULL, WM_OP_INVOKE_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "filepath", recent->filepath); + RNA_boolean_set(&ptr, "display_file_selector", false); } } else { diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index 2237e8b02bc..4c6f2231cc1 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -249,7 +249,7 @@ void ED_spacetype_userpref(void) art->init = userpref_navigation_region_init; art->draw = userpref_navigation_region_draw; art->listener = userpref_navigation_region_listener; - art->keymapflag = ED_KEYMAP_UI; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_NAVBAR; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c index a67e6c27acb..04ef2ed8118 100644 --- a/source/blender/editors/space_userpref/userpref_ops.c +++ b/source/blender/editors/space_userpref/userpref_ops.c @@ -48,7 +48,7 @@ static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op)) UI_theme_init_default(); UI_style_init_default(); WM_event_add_notifier(C, NC_WINDOW, NULL); - + U.runtime.is_dirty = true; return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 638c77fc3cb..cc76c151a29 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -41,7 +41,6 @@ #include "GPU_batch.h" #include "GPU_matrix.h" #include "GPU_state.h" -#include "GPU_framebuffer.h" #include "ED_mesh.h" @@ -51,8 +50,6 @@ #include "view3d_intern.h" /* bad level include */ -#include "../../draw/intern/draw_cache_impl.h" /* bad level include (temporary) */ - int view3d_effective_drawtype(const struct View3D *v3d) { if (v3d->shading.type == OB_RENDER) { @@ -61,24 +58,6 @@ int view3d_effective_drawtype(const struct View3D *v3d) return v3d->shading.type; } -static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt) -{ - if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0) { - return false; - } - - if (G.f & G_FLAG_BACKBUFSEL) { - return false; - } - - /* if its drawing textures with zbuf sel, then don't draw dots */ - if (dt == OB_TEXTURE && vd->shading.type == OB_TEXTURE) { - return false; - } - - return true; -} - /* OpenGL Circle Drawing - Tables for Optimized Drawing Speed */ /* 32 values of sin function (still same result!) */ #define CIRCLE_RESOL 32 @@ -138,216 +117,6 @@ bool view3d_camera_border_hack_test = false; /* ***************** BACKBUF SEL (BBS) ********* */ -/** See #DRW_shgroup_world_clip_planes_from_rv3d, same function for draw manager. */ -static void bbs_world_clip_planes_from_rv3d(GPUBatch *batch, const float world_clip_planes[6][4]) -{ - GPU_batch_uniform_4fv_array(batch, "WorldClipPlanes", 6, world_clip_planes[0]); -} - -static void bbs_mesh_verts(GPUBatch *batch, int offset, const float world_clip_planes[6][4]) -{ - GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE)); - - const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); - GPU_batch_uniform_1ui(batch, "offset", offset); - if (world_clip_planes != NULL) { - bbs_world_clip_planes_from_rv3d(batch, world_clip_planes); - } - GPU_batch_draw(batch); -} - -static void bbs_mesh_wire(GPUBatch *batch, int offset, const float world_clip_planes[6][4]) -{ - GPU_line_width(1.0f); - glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); - - const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); - GPU_batch_uniform_1ui(batch, "offset", offset); - if (world_clip_planes != NULL) { - bbs_world_clip_planes_from_rv3d(batch, world_clip_planes); - } - GPU_batch_draw(batch); - - glProvokingVertex(GL_LAST_VERTEX_CONVENTION); -} - -/* two options, facecolors or black */ -static void bbs_mesh_face(GPUBatch *batch, - const bool use_select, - const float world_clip_planes[6][4]) -{ - if (use_select) { - const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); - GPU_batch_uniform_1ui(batch, "offset", 1); - if (world_clip_planes != NULL) { - bbs_world_clip_planes_from_rv3d(batch, world_clip_planes); - } - GPU_batch_draw(batch); - } - else { - const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_UNIFORM_SELECT_ID, sh_cfg); - GPU_batch_uniform_1ui(batch, "id", 0); - if (world_clip_planes != NULL) { - bbs_world_clip_planes_from_rv3d(batch, world_clip_planes); - } - GPU_batch_draw(batch); - } -} - -static void bbs_mesh_face_dot(GPUBatch *batch, const float world_clip_planes[6][4]) -{ - const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); - GPU_batch_uniform_1ui(batch, "offset", 1); - if (world_clip_planes != NULL) { - bbs_world_clip_planes_from_rv3d(batch, world_clip_planes); - } - GPU_batch_draw(batch); -} - -static void bbs_mesh_solid_verts(Depsgraph *UNUSED(depsgraph), - Scene *UNUSED(scene), - Object *ob, - const float world_clip_planes[6][4]) -{ - Mesh *me = ob->data; - - GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); - GPUBatch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me); - DRW_mesh_batch_cache_create_requested(ob, me, NULL, false, true); - - /* Only draw faces to mask out verts, we don't want their selection ID's. */ - bbs_mesh_face(geom_faces, false, world_clip_planes); - bbs_mesh_verts(geom_verts, 1, world_clip_planes); - - bm_vertoffs = me->totvert + 1; -} - -static void bbs_mesh_solid_faces(Scene *UNUSED(scene), - Object *ob, - const float world_clip_planes[6][4]) -{ - Mesh *me = ob->data; - Mesh *me_orig = DEG_get_original_object(ob)->data; - - const bool use_hide = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL); - GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); - DRW_mesh_batch_cache_create_requested(ob, me, NULL, false, use_hide); - - bbs_mesh_face(geom_faces, true, world_clip_planes); -} - -void draw_object_select_id(Depsgraph *depsgraph, - Scene *scene, - View3D *v3d, - RegionView3D *rv3d, - Object *ob, - short select_mode) -{ - ToolSettings *ts = scene->toolsettings; - if (select_mode == -1) { - select_mode = ts->selectmode; - } - - GPU_matrix_mul(ob->obmat); - GPU_depth_test(true); - - const float(*world_clip_planes)[4] = NULL; - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_local(rv3d, ob->obmat); - world_clip_planes = rv3d->clip_local; - } - - switch (ob->type) { - case OB_MESH: - if (ob->mode & OB_MODE_EDIT) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - const bool draw_facedot = check_ob_drawface_dot(scene, v3d, ob->dt); - const bool use_faceselect = (select_mode & SCE_SELECT_FACE) != 0; - - BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE); - - GPUBatch *geom_faces, *geom_edges, *geom_verts, *geom_facedots; - geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); - if (select_mode & SCE_SELECT_EDGE) { - geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(me); - } - if (select_mode & SCE_SELECT_VERTEX) { - geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me); - } - if (draw_facedot) { - geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(me); - } - DRW_mesh_batch_cache_create_requested(ob, me, NULL, false, true); - - bbs_mesh_face(geom_faces, use_faceselect, world_clip_planes); - - if (use_faceselect && draw_facedot) { - bbs_mesh_face_dot(geom_facedots, world_clip_planes); - } - - if (select_mode & SCE_SELECT_FACE) { - bm_solidoffs = 1 + em->bm->totface; - } - else { - bm_solidoffs = 1; - } - - ED_view3d_polygon_offset(rv3d, 1.0); - - /* we draw edges if edge select mode */ - if (select_mode & SCE_SELECT_EDGE) { - bbs_mesh_wire(geom_edges, bm_solidoffs, world_clip_planes); - bm_wireoffs = bm_solidoffs + em->bm->totedge; - } - else { - /* `bm_vertoffs` is calculated from `bm_wireoffs`. (otherwise see T53512) */ - bm_wireoffs = bm_solidoffs; - } - - ED_view3d_polygon_offset(rv3d, 1.1); - - /* we draw verts if vert select mode. */ - if (select_mode & SCE_SELECT_VERTEX) { - bbs_mesh_verts(geom_verts, bm_wireoffs, world_clip_planes); - bm_vertoffs = bm_wireoffs + em->bm->totvert; - } - else { - bm_vertoffs = bm_wireoffs; - } - - ED_view3d_polygon_offset(rv3d, 0.0); - } - else { - Mesh *me = DEG_get_original_object(ob)->data; - if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) && - /* currently vertex select supports weight paint and vertex paint*/ - ((ob->mode & OB_MODE_WEIGHT_PAINT) || (ob->mode & OB_MODE_VERTEX_PAINT))) { - bbs_mesh_solid_verts(depsgraph, scene, ob, world_clip_planes); - } - else { - bbs_mesh_solid_faces(scene, ob, world_clip_planes); - } - } - break; - case OB_CURVE: - case OB_SURF: - break; - } - - GPU_matrix_set(rv3d->viewmat); -} - void ED_draw_object_facemap(Depsgraph *depsgraph, Object *ob, const float col[4], diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 9ee7bb3066d..c1891865d6d 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1131,6 +1131,9 @@ static void view3d_header_region_listener(wmWindow *UNUSED(win), ED_region_tag_redraw(ar); } break; + case NC_BRUSH: + ED_region_tag_redraw(ar); + break; } /* From topbar, which ones are needed? split per header? */ @@ -1200,9 +1203,106 @@ static void view3d_buttons_region_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void view3d_buttons_region_draw(const bContext *C, ARegion *ar) +void ED_view3d_buttons_region_layout_ex(const bContext *C, + ARegion *ar, + const char *category_override) { - ED_region_panels_ex(C, ar, (const char *[]){CTX_data_mode_string(C), NULL}, -1, true); + const enum eContextObjectMode mode = CTX_data_mode_enum(C); + + const char *contexts_base[4] = {NULL}; + contexts_base[0] = CTX_data_mode_string(C); + + const char **contexts = &contexts_base[1]; + + switch (mode) { + case CTX_MODE_EDIT_MESH: + ARRAY_SET_ITEMS(contexts, ".mesh_edit"); + break; + case CTX_MODE_EDIT_CURVE: + ARRAY_SET_ITEMS(contexts, ".curve_edit"); + break; + case CTX_MODE_EDIT_SURFACE: + ARRAY_SET_ITEMS(contexts, ".curve_edit"); + break; + case CTX_MODE_EDIT_TEXT: + ARRAY_SET_ITEMS(contexts, ".text_edit"); + break; + case CTX_MODE_EDIT_ARMATURE: + ARRAY_SET_ITEMS(contexts, ".armature_edit"); + break; + case CTX_MODE_EDIT_METABALL: + ARRAY_SET_ITEMS(contexts, ".mball_edit"); + break; + case CTX_MODE_EDIT_LATTICE: + ARRAY_SET_ITEMS(contexts, ".lattice_edit"); + break; + case CTX_MODE_POSE: + ARRAY_SET_ITEMS(contexts, ".posemode"); + break; + case CTX_MODE_SCULPT: + ARRAY_SET_ITEMS(contexts, ".paint_common", ".sculpt_mode"); + break; + case CTX_MODE_PAINT_WEIGHT: + ARRAY_SET_ITEMS(contexts, ".paint_common", ".weightpaint"); + break; + case CTX_MODE_PAINT_VERTEX: + ARRAY_SET_ITEMS(contexts, ".paint_common", ".vertexpaint"); + break; + case CTX_MODE_PAINT_TEXTURE: + ARRAY_SET_ITEMS(contexts, ".paint_common", ".imagepaint"); + break; + case CTX_MODE_PARTICLE: + ARRAY_SET_ITEMS(contexts, ".paint_common", ".particlemode"); + break; + case CTX_MODE_OBJECT: + ARRAY_SET_ITEMS(contexts, ".objectmode"); + break; + case CTX_MODE_PAINT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_paint"); + break; + case CTX_MODE_SCULPT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt"); + break; + case CTX_MODE_WEIGHT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_weight"); + break; + default: + break; + } + + switch (mode) { + case CTX_MODE_PAINT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_paint"); + break; + case CTX_MODE_SCULPT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt"); + break; + case CTX_MODE_WEIGHT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_weight"); + break; + case CTX_MODE_EDIT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_edit"); + break; + default: + break; + } + + ListBase *paneltypes = &ar->type->paneltypes; + + /* Allow drawing 3D view toolbar from non 3D view space type. */ + if (category_override != NULL) { + SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D); + ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_UI); + paneltypes = &art->paneltypes; + } + + const bool vertical = true; + ED_region_panels_layout_ex(C, ar, paneltypes, contexts_base, -1, vertical, category_override); +} + +static void view3d_buttons_region_layout(const bContext *C, ARegion *ar) +{ + ED_view3d_buttons_region_layout_ex(C, ar, NULL); } static void view3d_buttons_region_listener(wmWindow *UNUSED(win), @@ -1507,11 +1607,13 @@ void ED_spacetype_view3d(void) /* regions: listview/buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d buttons region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 180; /* XXX */ + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = view3d_buttons_region_listener; + art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_ui; art->init = view3d_buttons_region_init; - art->draw = view3d_buttons_region_draw; + art->layout = view3d_buttons_region_layout; + art->draw = ED_region_panels_draw; BLI_addhead(&st->regiontypes, art); view3d_buttons_register(art); @@ -1535,9 +1637,9 @@ void ED_spacetype_view3d(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; art->listener = view3d_header_region_listener; + art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_header; art->init = view3d_header_region_init; art->draw = view3d_header_region_draw; - art->message_subscribe = view3d_header_region_message_subscribe; BLI_addhead(&st->regiontypes, art); /* regions: header */ @@ -1546,9 +1648,9 @@ void ED_spacetype_view3d(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; art->listener = view3d_header_region_listener; + art->message_subscribe = view3d_header_region_message_subscribe; art->init = view3d_header_region_init; art->draw = view3d_header_region_draw; - art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_header; BLI_addhead(&st->regiontypes, art); /* regions: hud */ diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 8c5f1c16438..2ce67bfbe4c 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -105,7 +105,8 @@ void ED_view3d_update_viewmat(Depsgraph *depsgraph, ARegion *ar, float viewmat[4][4], float winmat[4][4], - const rcti *rect) + const rcti *rect, + bool offscreen) { RegionView3D *rv3d = ar->regiondata; @@ -138,7 +139,7 @@ void ED_view3d_update_viewmat(Depsgraph *depsgraph, /* calculate GLSL view dependent values */ /* store window coordinates scaling/offset */ - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + if (!offscreen && rv3d->persp == RV3D_CAMOB && v3d->camera) { rctf cameraborder; ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &cameraborder, false); rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); @@ -184,7 +185,22 @@ static void view3d_main_region_setup_view(Depsgraph *depsgraph, { RegionView3D *rv3d = ar->regiondata; - ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, viewmat, winmat, rect); + ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, viewmat, winmat, rect, false); + + /* set for opengl */ + GPU_matrix_projection_set(rv3d->winmat); + GPU_matrix_set(rv3d->viewmat); +} + +static void view3d_main_region_setup_offscreen(Depsgraph *depsgraph, + Scene *scene, + View3D *v3d, + ARegion *ar, + float viewmat[4][4], + float winmat[4][4]) +{ + RegionView3D *rv3d = ar->regiondata; + ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, viewmat, winmat, NULL, true); /* set for opengl */ GPU_matrix_projection_set(rv3d->winmat); @@ -1480,14 +1496,14 @@ static void view3d_stereo3d_setup_offscreen(Depsgraph *depsgraph, const bool is_left = STREQ(viewname, STEREO_LEFT_NAME); BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); - view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL); + view3d_main_region_setup_offscreen(depsgraph, scene, v3d, ar, viewmat, winmat); } else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ float viewmat[4][4]; Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); - view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL); + view3d_main_region_setup_offscreen(depsgraph, scene, v3d, ar, viewmat, winmat); } } @@ -1503,7 +1519,6 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph, bool do_sky, bool UNUSED(is_persp), const char *viewname, - GPUFXSettings *UNUSED(fx_settings), const bool do_color_management, GPUOffScreen *ofs, GPUViewport *viewport) @@ -1546,7 +1561,7 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph, view3d_stereo3d_setup_offscreen(depsgraph, scene, v3d, ar, winmat, viewname); } else { - view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL); + view3d_main_region_setup_offscreen(depsgraph, scene, v3d, ar, viewmat, winmat); } /* main drawing call */ @@ -1580,7 +1595,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, int sizex, int sizey, uint flag, - uint draw_flags, int alpha_mode, int samples, const char *viewname, @@ -1590,10 +1604,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, { RegionView3D *rv3d = ar->regiondata; const bool draw_sky = (alpha_mode == R_ADDSKY); - const bool use_full_sample = (draw_flags & V3D_OFSDRAW_USE_FULL_SAMPLE); /* view state */ - GPUFXSettings fx_settings = v3d->fx_settings; bool is_ortho = false; float winmat[4][4]; @@ -1613,7 +1625,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, if (own_ofs) { /* bind */ - ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, true, false, err_out); + ofs = GPU_offscreen_create(sizex, sizey, samples, true, false, err_out); if (ofs == NULL) { DRW_opengl_context_disable(); return NULL; @@ -1640,8 +1652,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, BKE_camera_params_compute_viewplane(¶ms, sizex, sizey, scene->r.xasp, scene->r.yasp); BKE_camera_params_compute_matrix(¶ms); - BKE_camera_to_gpu_dof(camera, &fx_settings); - is_ortho = params.is_ortho; copy_m4_m4(winmat, params.winmat); } @@ -1671,123 +1681,28 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, } } - if ((samples && use_full_sample) == 0) { - const bool do_color_management = (ibuf->rect_float == NULL); - /* Single-pass render, common case */ - ED_view3d_draw_offscreen(depsgraph, - scene, - drawtype, - v3d, - ar, - sizex, - sizey, - NULL, - winmat, - draw_sky, - !is_ortho, - viewname, - &fx_settings, - do_color_management, - ofs, - NULL); - - if (ibuf->rect_float) { - GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); - } - else if (ibuf->rect) { - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect); - } - } - else { - /* Multi-pass render, use accumulation buffer & jitter for 'full' oversampling. - * Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */ - static float jit_ofs[32][2]; - float winmat_jitter[4][4]; - float *rect_temp = (ibuf->rect_float) ? - ibuf->rect_float : - MEM_mallocN(sizex * sizey * sizeof(float[4]), "rect_temp"); - float *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(float[4]), "accum_buffer"); - GPUViewport *viewport = GPU_viewport_create_from_offscreen(ofs); - - BLI_jitter_init(jit_ofs, samples); - - /* first sample buffer, also initializes 'rv3d->persmat' */ - ED_view3d_draw_offscreen(depsgraph, - scene, - drawtype, - v3d, - ar, - sizex, - sizey, - NULL, - winmat, - draw_sky, - !is_ortho, - viewname, - &fx_settings, - false, - ofs, - viewport); - GPU_offscreen_read_pixels(ofs, GL_FLOAT, accum_buffer); - - /* skip the first sample */ - for (int j = 1; j < samples; j++) { - copy_m4_m4(winmat_jitter, winmat); - window_translate_m4(winmat_jitter, - rv3d->persmat, - (jit_ofs[j][0] * 2.0f) / sizex, - (jit_ofs[j][1] * 2.0f) / sizey); - - ED_view3d_draw_offscreen(depsgraph, - scene, - drawtype, - v3d, - ar, - sizex, - sizey, - NULL, - winmat_jitter, - draw_sky, - !is_ortho, - viewname, - &fx_settings, - false, - ofs, - viewport); - GPU_offscreen_read_pixels(ofs, GL_FLOAT, rect_temp); - - uint i = sizex * sizey * 4; - while (i--) { - accum_buffer[i] += rect_temp[i]; - } - } - - { - /* don't free data owned by 'ofs' */ - GPU_viewport_clear_from_offscreen(viewport); - GPU_viewport_free(viewport); - } - - if (ibuf->rect_float == NULL) { - MEM_freeN(rect_temp); - } - - if (ibuf->rect_float) { - float *rect_float = ibuf->rect_float; - uint i = sizex * sizey * 4; - while (i--) { - rect_float[i] = accum_buffer[i] / samples; - } - } - else { - uchar *rect_ub = (uchar *)ibuf->rect; - uint i = sizex * sizey * 4; - while (i--) { - rect_ub[i] = (uchar)(255.0f * accum_buffer[i] / samples); - } - } + const bool do_color_management = (ibuf->rect_float == NULL); + ED_view3d_draw_offscreen(depsgraph, + scene, + drawtype, + v3d, + ar, + sizex, + sizey, + NULL, + winmat, + draw_sky, + !is_ortho, + viewname, + do_color_management, + ofs, + NULL); - MEM_freeN(accum_buffer); + if (ibuf->rect_float) { + GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); + } + else if (ibuf->rect) { + GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect); } /* unbind */ @@ -1896,7 +1811,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph, width, height, flag, - draw_flags, alpha_mode, samples, viewname, diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c index b0cee18f8e3..755852a2e18 100644 --- a/source/blender/editors/space_view3d/view3d_draw_legacy.c +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -77,6 +77,7 @@ #include "ED_armature.h" #include "ED_keyframing.h" #include "ED_gpencil.h" +#include "ED_mesh.h" #include "ED_screen.h" #include "ED_space_api.h" #include "ED_screen_types.h" @@ -151,13 +152,11 @@ void ED_view3d_clipping_enable(void) /* *********************** backdraw for selection *************** */ -static void validate_object_select_id(struct Depsgraph *depsgraph, - Scene *scene, - ARegion *ar, - View3D *v3d, - Object *obact, - Object *obedit, - short select_mode) +/** + * \note Only use in object mode. + */ +static void validate_object_select_id( + struct Depsgraph *depsgraph, Scene *scene, ARegion *ar, View3D *v3d, Object *obact) { RegionView3D *rv3d = ar->regiondata; Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id); @@ -177,9 +176,6 @@ static void validate_object_select_id(struct Depsgraph *depsgraph, else if ((obact_eval && (obact_eval->mode & OB_MODE_PARTICLE_EDIT)) && !XRAY_ENABLED(v3d)) { /* do nothing */ } - else if ((obedit && (obedit->mode & OB_MODE_EDIT)) && !XRAY_FLAG_ENABLED(v3d)) { - /* do nothing */ - } else { v3d->flag &= ~V3D_INVALID_BACKBUF; return; @@ -189,34 +185,25 @@ static void validate_object_select_id(struct Depsgraph *depsgraph, return; } -#if 0 - if (test) { - if (qtest()) { - addafterqueue(ar->win, BACKBUFDRAW, 1); - return; - } - } -#endif - -#if 0 /* v3d->zbuf deprecated */ - if (v3d->shading.type > OB_WIRE) { - v3d->zbuf = true; - } -#endif - - G.f |= G_FLAG_BACKBUFSEL; - if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) { + uint dummy_vert_ofs, dummy_edge_ofs, dummy_face_ofs; DRW_framebuffer_select_id_setup(ar, true); - draw_object_select_id(depsgraph, scene_eval, v3d, rv3d, obact_eval, select_mode); + DRW_draw_select_id_object(scene_eval, + rv3d, + obact_eval, + scene->toolsettings->selectmode, + false, + 1, + &dummy_vert_ofs, + &dummy_edge_ofs, + &dummy_face_ofs); + DRW_framebuffer_select_id_release(ar); } /* TODO: Create a flag in `DRW_manager` because the drawing is no longer * made on the backbuffer in this case. */ v3d->flag &= ~V3D_INVALID_BACKBUF; - - G.f &= ~G_FLAG_BACKBUFSEL; } /* TODO: Creating, attaching texture, and destroying a framebuffer is quite slow. @@ -241,21 +228,15 @@ static void view3d_opengl_read_Z_pixels(GPUViewport *viewport, rcti *rect, void GPU_framebuffer_free(tmp_fb); } -void ED_view3d_select_id_validate_with_select_mode(ViewContext *vc, short select_mode) +void ED_view3d_select_id_validate(ViewContext *vc) { /* TODO: Create a flag in `DRW_manager` because the drawing is no longer * made on the backbuffer in this case. */ if (vc->v3d->flag & V3D_INVALID_BACKBUF) { - validate_object_select_id( - vc->depsgraph, vc->scene, vc->ar, vc->v3d, vc->obact, vc->obedit, select_mode); + validate_object_select_id(vc->depsgraph, vc->scene, vc->ar, vc->v3d, vc->obact); } } -void ED_view3d_select_id_validate(ViewContext *vc) -{ - ED_view3d_select_id_validate_with_select_mode(vc, -1); -} - void ED_view3d_backbuf_depth_validate(ViewContext *vc) { if (vc->v3d->flag & V3D_INVALID_BACKBUF) { @@ -271,10 +252,8 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc) } } -uint *ED_view3d_select_id_read_rect(ViewContext *vc, const rcti *clip, uint *r_buf_len) +uint *ED_view3d_select_id_read_rect(const rcti *clip, uint *r_buf_len) { - ED_view3d_select_id_validate(vc); - uint width = BLI_rcti_size_x(clip); uint height = BLI_rcti_size_y(clip); uint buf_len = width * height; @@ -298,25 +277,8 @@ int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist) return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx)); } -/* samples a single pixel (copied from vpaint) */ -uint ED_view3d_select_id_sample(ViewContext *vc, int x, int y) -{ - if (x >= vc->ar->winx || y >= vc->ar->winy) { - return 0; - } - - uint buf_len; - uint *buf = ED_view3d_select_id_read(vc, x, y, x, y, &buf_len); - BLI_assert(0 != buf_len); - uint ret = buf[0]; - MEM_freeN(buf); - - return ret; -} - /* reads full rect, converts indices */ -uint *ED_view3d_select_id_read( - ViewContext *vc, int xmin, int ymin, int xmax, int ymax, uint *r_buf_len) +uint *ED_view3d_select_id_read(int xmin, int ymin, int xmax, int ymax, uint *r_buf_len) { if (UNLIKELY((xmin > xmax) || (ymin > ymax))) { return NULL; @@ -330,7 +292,7 @@ uint *ED_view3d_select_id_read( }; uint buf_len; - uint *buf = ED_view3d_select_id_read_rect(vc, &rect, &buf_len); + uint *buf = ED_view3d_select_id_read_rect(&rect, &buf_len); if (r_buf_len) { *r_buf_len = buf_len; @@ -339,85 +301,6 @@ uint *ED_view3d_select_id_read( return buf; } -/* smart function to sample a rect spiralling outside, nice for backbuf selection */ -uint ED_view3d_select_id_read_nearest(struct ViewContext *UNUSED(vc), - const int mval[2], - const uint id_min, - const uint id_max, - uint *r_dist) -{ - /* Create region around mouse cursor. This must be square and have an odd - * width, the spiraling algorithm does not work with arbitrary rectangles. */ - rcti rect; - BLI_rcti_init_pt_radius(&rect, mval, *r_dist); - rect.xmax += 1; - rect.ymax += 1; - - int width = BLI_rcti_size_x(&rect); - int height = width; - BLI_assert(width == height); - - /* Read from selection framebuffer. */ - uint *buf = MEM_mallocN(width * height * sizeof(*buf), __func__); - DRW_framebuffer_select_id_read(&rect, buf); - - /* Spiral, starting from center of buffer. */ - int spiral_offset = height * (int)(width / 2) + (height / 2); - int spiral_direction = 0; - - uint index = 0; - - for (int nr = 1; nr <= height; nr++) { - for (int a = 0; a < 2; a++) { - for (int b = 0; b < nr; b++) { - /* Find hit within the specified range. */ - uint hit_id = buf[spiral_offset]; - - if (hit_id && hit_id >= id_min && hit_id < id_max) { - /* Get x/y from spiral offset. */ - int hit_x = spiral_offset % width; - int hit_y = spiral_offset / width; - - int center_x = width / 2; - int center_y = height / 2; - - /* Manhatten distance in keeping with other screen-based selection. */ - *r_dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y)); - - /* Indices start at 1 here. */ - index = (hit_id - id_min) + 1; - goto exit; - } - - /* Next spiral step. */ - if (spiral_direction == 0) { - spiral_offset += 1; /* right */ - } - else if (spiral_direction == 1) { - spiral_offset -= width; /* down */ - } - else if (spiral_direction == 2) { - spiral_offset -= 1; /* left */ - } - else { - spiral_offset += width; /* up */ - } - - /* Stop if we are outside the buffer. */ - if (spiral_offset < 0 || spiral_offset >= width * height) { - goto exit; - } - } - - spiral_direction = (spiral_direction + 1) % 4; - } - } - -exit: - MEM_freeN(buf); - return index; -} - /* ************************************************************* */ static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser) diff --git a/source/blender/editors/space_view3d/view3d_gizmo_camera.c b/source/blender/editors/space_view3d/view3d_gizmo_camera.c index 0b8c3b8cd28..5fe62a74d4b 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_camera.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c @@ -154,7 +154,7 @@ static void WIDGETGROUP_camera_refresh(const bContext *C, wmGizmoGroup *gzgroup) /* need to set property here for undo. TODO would prefer to do this in _init */ WM_gizmo_target_property_def_rna( - cagzgroup->dop_dist, "offset", &camera_ptr, "dof_distance", -1); + cagzgroup->dop_dist, "offset", &camera_ptr, "dof.focus_distance", -1); } else { WM_gizmo_set_flag(cagzgroup->dop_dist, WM_GIZMO_HIDDEN, true); @@ -262,7 +262,7 @@ static void WIDGETGROUP_camera_message_subscribe(const bContext *C, }; { - extern PropertyRNA rna_Camera_dof_distance; + extern PropertyRNA rna_CameraDOFSettings_focus_distance; extern PropertyRNA rna_Camera_display_size; extern PropertyRNA rna_Camera_ortho_scale; extern PropertyRNA rna_Camera_sensor_fit; @@ -273,7 +273,7 @@ static void WIDGETGROUP_camera_message_subscribe(const bContext *C, extern PropertyRNA rna_Camera_type; extern PropertyRNA rna_Camera_lens; const PropertyRNA *props[] = { - &rna_Camera_dof_distance, + &rna_CameraDOFSettings_focus_distance, &rna_Camera_display_size, &rna_Camera_ortho_scale, &rna_Camera_sensor_fit, diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c index 6f35c0aa748..9cbf179ab49 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c @@ -304,15 +304,14 @@ static int gizmo_preselect_edgering_test_select(bContext *C, wmGizmo *gz, const em_setup_viewcontext(C, &vc); copy_v2_v2_int(vc.mval, mval); - for (uint base_index = 0; base_index < gz_ring->bases_len; base_index++) { - Object *ob_iter = gz_ring->bases[base_index]->object; - ED_view3d_viewcontext_init_object(&vc, ob_iter); - BMEdge *eed_test = EDBM_edge_find_nearest_ex(&vc, &best.dist, NULL, false, false, NULL); - if (eed_test) { - best.ob = ob_iter; - best.eed = eed_test; - best.base_index = base_index; - } + uint base_index; + BMEdge *eed_test = EDBM_edge_find_nearest_ex( + &vc, &best.dist, NULL, false, false, NULL, gz_ring->bases, gz_ring->bases_len, &base_index); + + if (eed_test) { + best.ob = gz_ring->bases[base_index]->object; + best.eed = eed_test; + best.base_index = base_index; } BMesh *bm = NULL; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 9075909a6fe..e499672acc1 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -127,13 +127,6 @@ void VIEW3D_OT_fly(struct wmOperatorType *ot); void VIEW3D_OT_walk(struct wmOperatorType *ot); /* drawobject.c */ -void draw_object_select_id(struct Depsgraph *depsgraph, - Scene *scene, - View3D *v3d, - RegionView3D *rv3d, - struct Object *ob, - short select_mode); - int view3d_effective_drawtype(const struct View3D *v3d); /* view3d_draw.c */ diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 2ce23486476..b3b4910c525 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -41,6 +41,7 @@ #include "MEM_guardedalloc.h" #include "BLI_array.h" +#include "BLI_bitmap.h" #include "BLI_math.h" #include "BLI_lasso_2d.h" #include "BLI_rect.h" @@ -57,6 +58,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "BKE_global.h" +#include "BKE_main.h" #include "BKE_armature.h" #include "BKE_context.h" @@ -87,6 +89,7 @@ #include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_buffer_utils.h" #include "ED_select_utils.h" #include "ED_sculpt.h" #include "ED_mball.h" @@ -134,9 +137,6 @@ void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact) if (vc->obedit) { BLI_assert(BKE_object_is_in_editmode(obact)); vc->obedit = obact; - /* previous selections are now invalid. */ - vc->v3d->flag |= V3D_INVALID_BACKBUF; - if (vc->em) { vc->em = BKE_editmesh_from_object(vc->obedit); } @@ -181,20 +181,96 @@ static bool object_deselect_all_except(ViewLayer *view_layer, Base *b) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Internal Edit-Mesh Select Buffer Wrapper + * + * Avoid duplicate code when using edit-mode selection, + * actual logic is handled outside of this function. + * + * \note Currently this #EDBMSelectID_Context which is mesh specific + * however the logic could also be used for non-meshes too. + * + * \{ */ + +struct EditSelectBuf_Cache { + Base **bases; + uint bases_len; + struct EDBMSelectID_Context *sel_id_ctx; + BLI_bitmap *select_bitmap; +}; + +static void editselect_buf_cache_init(struct EditSelectBuf_Cache *esel, ViewContext *vc) +{ + if (vc->obedit) { + esel->bases = BKE_view_layer_array_from_bases_in_edit_mode( + vc->view_layer, vc->v3d, &esel->bases_len); + } + else { + /* Use for paint modes, currently only a single object at a time. */ + if (vc->obact) { + esel->bases = MEM_mallocN(sizeof(esel->bases), __func__); + esel->bases[0] = BKE_view_layer_base_find(vc->view_layer, vc->obact); + esel->bases_len = 1; + } + else { + esel->bases = NULL; + esel->bases_len = 0; + } + } + esel->sel_id_ctx = EDBM_select_id_context_create( + vc, esel->bases, esel->bases_len, vc->scene->toolsettings->selectmode); + for (int i = 0; i < esel->bases_len; i++) { + esel->bases[i]->object->runtime.select_id = i; + } +} + +static void editselect_buf_cache_free(struct EditSelectBuf_Cache *esel) +{ + if (esel->sel_id_ctx) { + EDBM_select_id_context_destroy(esel->sel_id_ctx); + } + MEM_SAFE_FREE(esel->select_bitmap); + MEM_SAFE_FREE(esel->bases); +} + +static void editselect_buf_cache_free_voidp(void *esel_voidp) +{ + editselect_buf_cache_free(esel_voidp); + MEM_freeN(esel_voidp); +} + +static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *wm_userdata, + ViewContext *vc) +{ + struct EditSelectBuf_Cache *esel = MEM_callocN(sizeof(*esel), __func__); + wm_userdata->data = esel; + wm_userdata->free_fn = editselect_buf_cache_free_voidp; + wm_userdata->use_free = true; + editselect_buf_cache_init(esel, vc); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Internal Edit-Mesh Utilities * \{ */ -static bool edbm_backbuf_check_and_select_verts(BMEditMesh *em, const eSelectOp sel_op) +static bool edbm_backbuf_check_and_select_verts(struct EditSelectBuf_Cache *esel, + Object *ob, + BMEditMesh *em, + const eSelectOp sel_op) { BMVert *eve; BMIter iter; - uint index = bm_wireoffs; bool changed = false; + const BLI_bitmap *select_bitmap = esel->select_bitmap; + uint index = EDBM_select_id_context_offset_for_object_elem( + esel->sel_id_ctx, ob->runtime.select_id, BM_VERT); + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); - const bool is_inside = EDBM_backbuf_check(index); + const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_vert_select_set(em->bm, eve, sel_op_result); @@ -206,17 +282,23 @@ static bool edbm_backbuf_check_and_select_verts(BMEditMesh *em, const eSelectOp return changed; } -static bool edbm_backbuf_check_and_select_edges(BMEditMesh *em, const eSelectOp sel_op) +static bool edbm_backbuf_check_and_select_edges(struct EditSelectBuf_Cache *esel, + Object *ob, + BMEditMesh *em, + const eSelectOp sel_op) { BMEdge *eed; BMIter iter; - uint index = bm_solidoffs; bool changed = false; + const BLI_bitmap *select_bitmap = esel->select_bitmap; + uint index = EDBM_select_id_context_offset_for_object_elem( + esel->sel_id_ctx, ob->runtime.select_id, BM_EDGE); + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); - const bool is_inside = EDBM_backbuf_check(index); + const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_edge_select_set(em->bm, eed, sel_op_result); @@ -228,17 +310,23 @@ static bool edbm_backbuf_check_and_select_edges(BMEditMesh *em, const eSelectOp return changed; } -static bool edbm_backbuf_check_and_select_faces(BMEditMesh *em, const eSelectOp sel_op) +static bool edbm_backbuf_check_and_select_faces(struct EditSelectBuf_Cache *esel, + Object *ob, + BMEditMesh *em, + const eSelectOp sel_op) { BMFace *efa; BMIter iter; - uint index = 1; bool changed = false; + const BLI_bitmap *select_bitmap = esel->select_bitmap; + uint index = EDBM_select_id_context_offset_for_object_elem( + esel->sel_id_ctx, ob->runtime.select_id, BM_FACE); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); - const bool is_inside = EDBM_backbuf_check(index); + const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_face_select_set(em->bm, efa, sel_op_result); @@ -251,17 +339,21 @@ static bool edbm_backbuf_check_and_select_faces(BMEditMesh *em, const eSelectOp } /* object mode, edbm_ prefix is confusing here, rename? */ -static bool edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const eSelectOp sel_op) +static bool edbm_backbuf_check_and_select_verts_obmode(Mesh *me, + struct EditSelectBuf_Cache *esel, + const eSelectOp sel_op) { MVert *mv = me->mvert; uint index; bool changed = false; + const BLI_bitmap *select_bitmap = esel->select_bitmap; + if (mv) { - for (index = 1; index <= me->totvert; index++, mv++) { + for (index = 0; index < me->totvert; index++, mv++) { if (!(mv->flag & ME_HIDE)) { const bool is_select = mv->flag & SELECT; - const bool is_inside = EDBM_backbuf_check(index); + const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT); @@ -274,17 +366,21 @@ static bool edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const eSelectOp } /* object mode, edbm_ prefix is confusing here, rename? */ -static bool edbm_backbuf_check_and_select_tfaces(Mesh *me, const eSelectOp sel_op) +static bool edbm_backbuf_check_and_select_faces_obmode(Mesh *me, + struct EditSelectBuf_Cache *esel, + const eSelectOp sel_op) { MPoly *mpoly = me->mpoly; uint index; bool changed = false; + const BLI_bitmap *select_bitmap = esel->select_bitmap; + if (mpoly) { - for (index = 1; index <= me->totpoly; index++, mpoly++) { + for (index = 0; index < me->totpoly; index++, mpoly++) { if (!(mpoly->flag & ME_HIDE)) { const bool is_select = mpoly->flag & ME_FACE_SEL; - const bool is_inside = EDBM_backbuf_check(index); + const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL); @@ -623,14 +719,26 @@ static void do_lasso_select_mesh__doSelectVert(void *userData, data->is_changed = true; } } -static void do_lasso_select_mesh__doSelectEdge_pass0( - void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) -{ - LassoSelectUserData *data = userData; +struct LassoSelectUserData_ForMeshEdge { + LassoSelectUserData *data; + struct EditSelectBuf_Cache *esel; + uint backbuf_offset; +}; +static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data, + BMEdge *eed, + const float screen_co_a[2], + const float screen_co_b[2], + int index) +{ + struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data; + LassoSelectUserData *data = data_for_edge->data; + const bool is_visible = (data_for_edge->esel ? + BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, + data_for_edge->backbuf_offset + index) : + true); const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); const bool is_inside = - (EDBM_backbuf_check(bm_solidoffs + index) && - edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && + (is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) && BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); @@ -640,15 +748,24 @@ static void do_lasso_select_mesh__doSelectEdge_pass0( data->is_changed = true; } } -static void do_lasso_select_mesh__doSelectEdge_pass1( - void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) +static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data, + BMEdge *eed, + const float screen_co_a[2], + const float screen_co_b[2], + int index) { - LassoSelectUserData *data = userData; + struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data; + LassoSelectUserData *data = data_for_edge->data; + const bool is_visible = (data_for_edge->esel ? + BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, + data_for_edge->backbuf_offset + index) : + true); const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); - const bool is_inside = - (EDBM_backbuf_check(bm_solidoffs + index) && - BLI_lasso_is_edge_inside( - data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), IS_CLIPPED)); + const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcords, + data->moves, + UNPACK2(screen_co_a), + UNPACK2(screen_co_b), + IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); @@ -674,6 +791,7 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, } static bool do_lasso_select_mesh(ViewContext *vc, + wmGenericUserData *wm_userdata, const int mcords[][2], short moves, const eSelectOp sel_op) @@ -681,7 +799,6 @@ static bool do_lasso_select_mesh(ViewContext *vc, LassoSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; rcti rect; - int bbsel; /* set editmesh */ vc->em = BKE_editmesh_from_object(vc->obedit); @@ -701,12 +818,22 @@ static bool do_lasso_select_mesh(ViewContext *vc, ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); GPU_matrix_set(vc->rv3d->viewmat); - bbsel = EDBM_backbuf_border_mask_init( - vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + + const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); + + struct EditSelectBuf_Cache *esel = wm_userdata->data; + if (use_zbuf) { + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_poly(buffer_len, mcords, moves, &rect); + } + } if (ts->selectmode & SCE_SELECT_VERTEX) { - if (bbsel) { - data.is_changed |= edbm_backbuf_check_and_select_verts(vc->em, sel_op); + if (use_zbuf) { + data.is_changed |= edbm_backbuf_check_and_select_verts(esel, vc->obedit, vc->em, sel_op); } else { mesh_foreachScreenVert( @@ -714,18 +841,26 @@ static bool do_lasso_select_mesh(ViewContext *vc, } } if (ts->selectmode & SCE_SELECT_EDGE) { - /* Does both bbsel and non-bbsel versions (need screen cos for both) */ + /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */ + struct LassoSelectUserData_ForMeshEdge data_for_edge = { + .data = &data, + .esel = use_zbuf ? esel : NULL, + .backbuf_offset = use_zbuf ? + EDBM_select_id_context_offset_for_object_elem( + esel->sel_id_ctx, vc->obedit->runtime.select_id, BM_EDGE) : + 0, + }; mesh_foreachScreenEdge( - vc, do_lasso_select_mesh__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR); + vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, V3D_PROJ_TEST_CLIP_NEAR); if (data.is_done == false) { mesh_foreachScreenEdge( - vc, do_lasso_select_mesh__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR); + vc, do_lasso_select_mesh__doSelectEdge_pass1, &data_for_edge, V3D_PROJ_TEST_CLIP_NEAR); } } if (ts->selectmode & SCE_SELECT_FACE) { - if (bbsel) { - data.is_changed |= edbm_backbuf_check_and_select_faces(vc->em, sel_op); + if (use_zbuf) { + data.is_changed |= edbm_backbuf_check_and_select_faces(esel, vc->obedit, vc->em, sel_op); } else { mesh_foreachScreenFace( @@ -733,8 +868,6 @@ static bool do_lasso_select_mesh(ViewContext *vc, } } - EDBM_backbuf_free(); - if (data.is_changed) { EDBM_selectmode_flush(vc->em); } @@ -975,6 +1108,7 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, } } static bool do_lasso_select_paintvert(ViewContext *vc, + wmGenericUserData *wm_userdata, const int mcords[][2], short moves, const eSelectOp sel_op) @@ -996,14 +1130,20 @@ static bool do_lasso_select_paintvert(ViewContext *vc, BLI_lasso_boundbox(&rect, mcords, moves); + struct EditSelectBuf_Cache *esel = wm_userdata->data; if (use_zbuf) { - bm_vertoffs = me->totvert + 1; /* max index array */ - - EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - - changed |= edbm_backbuf_check_and_select_verts_obmode(me, sel_op); + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_poly(buffer_len, mcords, moves, &rect); + } + } - EDBM_backbuf_free(); + if (use_zbuf) { + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op); + } } else { LassoSelectUserData data; @@ -1025,9 +1165,11 @@ static bool do_lasso_select_paintvert(ViewContext *vc, paintvert_flush_flags(ob); paintvert_tag_select_update(vc->C, ob); } + return changed; } static bool do_lasso_select_paintface(ViewContext *vc, + wmGenericUserData *wm_userdata, const int mcords[][2], short moves, const eSelectOp sel_op) @@ -1040,19 +1182,25 @@ static bool do_lasso_select_paintface(ViewContext *vc, return false; } - bm_vertoffs = me->totpoly + 1; /* max index array */ - - BLI_lasso_boundbox(&rect, mcords, moves); - EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - bool changed = false; if (SEL_OP_USE_PRE_DESELECT(sel_op)) { /* flush selection at the end */ changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false); } - changed |= edbm_backbuf_check_and_select_tfaces(me, sel_op); - EDBM_backbuf_free(); + BLI_lasso_boundbox(&rect, mcords, moves); + + struct EditSelectBuf_Cache *esel = wm_userdata->data; + if (esel == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_poly(buffer_len, mcords, moves, &rect); + } + + if (esel->select_bitmap) { + changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op); + } if (changed) { paintface_flush_flags(vc->C, ob, SELECT); @@ -1100,12 +1248,15 @@ static bool view3d_lasso_select( Object *ob = CTX_data_active_object(C); bool changed_multi = false; + wmGenericUserData wm_userdata_buf = {0}; + wmGenericUserData *wm_userdata = &wm_userdata_buf; + if (vc->obedit == NULL) { /* Object Mode */ if (BKE_paint_select_face_test(ob)) { - changed_multi |= do_lasso_select_paintface(vc, mcords, moves, sel_op); + changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcords, moves, sel_op); } else if (BKE_paint_select_vert_test(ob)) { - changed_multi |= do_lasso_select_paintvert(vc, mcords, moves, sel_op); + changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcords, moves, sel_op); } else if (ob && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { @@ -1122,14 +1273,13 @@ static bool view3d_lasso_select( } } else { /* Edit Mode */ - FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, vc->v3d, ob->type, ob->mode, ob_iter) { ED_view3d_viewcontext_init_object(vc, ob_iter); bool changed = false; switch (vc->obedit->type) { case OB_MESH: - changed = do_lasso_select_mesh(vc, mcords, moves, sel_op); + changed = do_lasso_select_mesh(vc, wm_userdata, mcords, moves, sel_op); break; case OB_CURVE: case OB_SURF: @@ -1157,6 +1307,9 @@ static bool view3d_lasso_select( } FOREACH_OBJECT_IN_MODE_END; } + + WM_generic_user_data_free(wm_userdata); + return changed_multi; } @@ -1170,6 +1323,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) if (mcords) { view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc); @@ -1337,7 +1491,7 @@ static Base *object_mouse_select_menu( if (buffer) { for (int a = 0; a < hits; a++) { /* index was converted */ - if (base->object->select_id == (buffer[(4 * a) + 3] & ~0xFFFF0000)) { + if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & ~0xFFFF0000)) { ok = true; break; } @@ -1609,7 +1763,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, else { /* only exclude active object when it is selected... */ if (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED) && hits > 1) { - notcol = BASACT(view_layer)->object->select_id; + notcol = BASACT(view_layer)->object->runtime.select_id; } for (a = 0; a < hits; a++) { @@ -1623,7 +1777,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, base = FIRSTBASE(view_layer); while (base) { if (BASE_SELECTABLE(v3d, base)) { - if (base->object->select_id == selcol) { + if (base->object->runtime.select_id == selcol) { break; } } @@ -1654,13 +1808,13 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, if (has_bones) { /* skip non-bone objects */ if ((buffer[4 * a + 3] & 0xFFFF0000)) { - if (base->object->select_id == (buffer[(4 * a) + 3] & 0xFFFF)) { + if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & 0xFFFF)) { basact = base; } } } else { - if (base->object->select_id == (buffer[(4 * a) + 3] & 0xFFFF)) { + if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & 0xFFFF)) { basact = base; } } @@ -1693,6 +1847,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) /* setup view context for argument to callbacks */ view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); ED_view3d_viewcontext_init(C, &vc); @@ -1878,7 +2033,7 @@ static bool ed_object_select_pick(bContext *C, /* if there's bundles in buffer select bundles first, * so non-camera elements should be ignored in buffer */ - if (basact->object->select_id != (hitresult & 0xFFFF)) { + if (basact->object->runtime.select_id != (hitresult & 0xFFFF)) { continue; } @@ -2129,6 +2284,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op) RNA_int_get_array(op->ptr, "location", location); view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); if (object) { obedit = NULL; @@ -2335,9 +2491,13 @@ static void do_paintvert_box_select__doSelectVert(void *userData, data->is_changed = true; } } -static bool do_paintvert_box_select(ViewContext *vc, const rcti *rect, const eSelectOp sel_op) +static bool do_paintvert_box_select(ViewContext *vc, + wmGenericUserData *wm_userdata, + const rcti *rect, + const eSelectOp sel_op) { const bool use_zbuf = !XRAY_ENABLED(vc->v3d); + Mesh *me; me = vc->obact->data; @@ -2354,48 +2514,16 @@ static bool do_paintvert_box_select(ViewContext *vc, const rcti *rect, const eSe /* pass */ } else if (use_zbuf) { - MVert *mvert; - unsigned int *rt; - int a, index; - char *selar; - - selar = MEM_callocN(me->totvert + 1, "selar"); - - uint buf_len; - uint *buf = ED_view3d_select_id_read_rect(vc, rect, &buf_len); - - rt = buf; - - a = buf_len; - while (a--) { - if (*rt) { - index = *rt; - if (index <= me->totvert) { - selar[index] = 1; - } - } - rt++; + struct EditSelectBuf_Cache *esel = wm_userdata->data; + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_rect(buffer_len, rect); } - - mvert = me->mvert; - for (a = 1; a <= me->totvert; a++, mvert++) { - if ((mvert->flag & ME_HIDE) == 0) { - const bool is_select = mvert->flag & SELECT; - const bool is_inside = (selar[a] != 0); - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); - if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(mvert->flag, sel_op_result, SELECT); - changed = true; - } - } + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op); } - - MEM_freeN(buf); - MEM_freeN(selar); - -#ifdef __APPLE__ - glReadBuffer(GL_BACK); -#endif } else { BoxSelectUserData data; @@ -2419,6 +2547,46 @@ static bool do_paintvert_box_select(ViewContext *vc, const rcti *rect, const eSe return changed; } +static bool do_paintface_box_select(ViewContext *vc, + wmGenericUserData *wm_userdata, + const rcti *rect, + int sel_op) +{ + Object *ob = vc->obact; + Mesh *me; + + me = BKE_mesh_from_object(ob); + if ((me == NULL) || (me->totpoly == 0)) { + return false; + } + + bool changed = false; + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + changed |= paintface_deselect_all_visible(vc->C, vc->obact, SEL_DESELECT, false); + } + + if (BLI_rcti_is_empty(rect)) { + /* pass */ + } + else { + struct EditSelectBuf_Cache *esel = wm_userdata->data; + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_rect(buffer_len, rect); + } + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op); + } + } + + if (changed) { + paintface_flush_flags(vc->C, vc->obact, SELECT); + } + return changed; +} + static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, @@ -2519,12 +2687,22 @@ static void do_mesh_box_select__doSelectVert(void *userData, data->is_changed = true; } } +struct BoxSelectUserData_ForMeshEdge { + BoxSelectUserData *data; + struct EditSelectBuf_Cache *esel; + uint backbuf_offset; +}; static void do_mesh_box_select__doSelectEdge_pass0( void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { - BoxSelectUserData *data = userData; + struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData; + BoxSelectUserData *data = data_for_edge->data; + const bool is_visible = (data_for_edge->esel ? + BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, + data_for_edge->backbuf_offset + index) : + true); const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); - const bool is_inside = (EDBM_backbuf_check(bm_solidoffs + index) && + const bool is_inside = (is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { @@ -2536,10 +2714,14 @@ static void do_mesh_box_select__doSelectEdge_pass0( static void do_mesh_box_select__doSelectEdge_pass1( void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { - BoxSelectUserData *data = userData; + struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData; + BoxSelectUserData *data = data_for_edge->data; + const bool is_visible = (data_for_edge->esel ? + BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, + data_for_edge->backbuf_offset + index) : + true); const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); - const bool is_inside = (EDBM_backbuf_check(bm_solidoffs + index) && - edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); + const bool is_inside = (is_visible && edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); @@ -2560,11 +2742,13 @@ static void do_mesh_box_select__doSelectFace(void *userData, data->is_changed = true; } } -static bool do_mesh_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op) +static bool do_mesh_box_select(ViewContext *vc, + wmGenericUserData *wm_userdata, + const rcti *rect, + const eSelectOp sel_op) { BoxSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; - int bbsel; view3d_userdata_boxselect_init(&data, vc, rect, sel_op); @@ -2579,11 +2763,22 @@ static bool do_mesh_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); GPU_matrix_set(vc->rv3d->viewmat); - bbsel = EDBM_backbuf_border_init(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + + const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); + + struct EditSelectBuf_Cache *esel = wm_userdata->data; + if (use_zbuf) { + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_rect(buffer_len, rect); + } + } if (ts->selectmode & SCE_SELECT_VERTEX) { - if (bbsel) { - data.is_changed |= edbm_backbuf_check_and_select_verts(vc->em, sel_op); + if (use_zbuf) { + data.is_changed |= edbm_backbuf_check_and_select_verts(esel, vc->obedit, vc->em, sel_op); } else { mesh_foreachScreenVert( @@ -2591,18 +2786,26 @@ static bool do_mesh_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_ } } if (ts->selectmode & SCE_SELECT_EDGE) { - /* Does both bbsel and non-bbsel versions (need screen cos for both) */ + /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */ + struct BoxSelectUserData_ForMeshEdge cb_data = { + .data = &data, + .esel = use_zbuf ? esel : NULL, + .backbuf_offset = use_zbuf ? + EDBM_select_id_context_offset_for_object_elem( + esel->sel_id_ctx, vc->obedit->runtime.select_id, BM_EDGE) : + 0, + }; mesh_foreachScreenEdge( - vc, do_mesh_box_select__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR); + vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, V3D_PROJ_TEST_CLIP_NEAR); if (data.is_done == false) { mesh_foreachScreenEdge( - vc, do_mesh_box_select__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR); + vc, do_mesh_box_select__doSelectEdge_pass1, &cb_data, V3D_PROJ_TEST_CLIP_NEAR); } } if (ts->selectmode & SCE_SELECT_FACE) { - if (bbsel) { - data.is_changed |= edbm_backbuf_check_and_select_faces(vc->em, sel_op); + if (use_zbuf) { + data.is_changed |= edbm_backbuf_check_and_select_faces(esel, vc->obedit, vc->em, sel_op); } else { mesh_foreachScreenFace( @@ -2610,8 +2813,6 @@ static bool do_mesh_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_ } } - EDBM_backbuf_free(); - if (data.is_changed) { EDBM_selectmode_flush(vc->em); } @@ -2652,7 +2853,7 @@ static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectO } const uint hit_object = hitresult & 0xFFFF; - if (vc->obedit->select_id != hit_object) { + if (vc->obedit->runtime.select_id != hit_object) { continue; } @@ -2803,7 +3004,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) { if (BASE_SELECTABLE(v3d, base)) { - if ((base->object->select_id & 0x0000FFFF) != 0) { + if ((base->object->runtime.select_id & 0x0000FFFF) != 0) { BLI_array_append(bases, base); } } @@ -2893,7 +3094,7 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e /* Select the next bone if we're not switching bases. */ if (col + 4 != col_end) { - if ((base->object->select_id & 0x0000FFFF) != (col[4] & 0x0000FFFF)) { + if ((base->object->runtime.select_id & 0x0000FFFF) != (col[4] & 0x0000FFFF)) { break; } if (base->object->pose != NULL) { @@ -2929,7 +3130,11 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) rcti rect; bool changed_multi = false; + wmGenericUserData wm_userdata_buf = {0}; + wmGenericUserData *wm_userdata = &wm_userdata_buf; + view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc); @@ -2938,7 +3143,6 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) WM_operator_properties_border_to_rcti(op, &rect); if (vc.obedit) { - FOREACH_OBJECT_IN_MODE_BEGIN ( vc.view_layer, vc.v3d, vc.obedit->type, vc.obedit->mode, ob_iter) { ED_view3d_viewcontext_init_object(&vc, ob_iter); @@ -2947,7 +3151,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) switch (vc.obedit->type) { case OB_MESH: vc.em = BKE_editmesh_from_object(vc.obedit); - changed = do_mesh_box_select(&vc, &rect, sel_op); + changed = do_mesh_box_select(&vc, wm_userdata, &rect, sel_op); if (changed) { DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); @@ -2997,10 +3201,10 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) C, &vc, &rect, sel_op == SEL_OP_ADD ? true : false); } else if (vc.obact && BKE_paint_select_face_test(vc.obact)) { - changed_multi = do_paintface_box_select(&vc, &rect, sel_op); + changed_multi = do_paintface_box_select(&vc, wm_userdata, &rect, sel_op); } else if (vc.obact && BKE_paint_select_vert_test(vc.obact)) { - changed_multi = do_paintvert_box_select(&vc, &rect, sel_op); + changed_multi = do_paintvert_box_select(&vc, wm_userdata, &rect, sel_op); } else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) { changed_multi = PE_box_select(C, &rect, sel_op); @@ -3013,6 +3217,8 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) } } + WM_generic_user_data_free(wm_userdata); + if (changed_multi) { return OPERATOR_FINISHED; } @@ -3118,10 +3324,13 @@ static void mesh_circle_doSelectFace(void *userData, } } -static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval[2], float rad) +static bool mesh_circle_select(ViewContext *vc, + wmGenericUserData *wm_userdata, + eSelectOp sel_op, + const int mval[2], + float rad) { ToolSettings *ts = vc->scene->toolsettings; - int bbsel; CircleSelectUserData data; vc->em = BKE_editmesh_from_object(vc->obedit); @@ -3134,14 +3343,30 @@ static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval } const bool select = (sel_op != SEL_OP_SUB); - bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); + + if (use_zbuf) { + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + } + } + struct EditSelectBuf_Cache *esel = wm_userdata->data; + + if (use_zbuf) { + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_circle(buffer_len, mval, (int)(rad + 1.0f)); + } + if (ts->selectmode & SCE_SELECT_VERTEX) { - if (bbsel) { - changed |= edbm_backbuf_check_and_select_verts(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + if (use_zbuf) { + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_verts( + esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + } } else { mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -3149,8 +3374,11 @@ static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval } if (ts->selectmode & SCE_SELECT_EDGE) { - if (bbsel) { - changed |= edbm_backbuf_check_and_select_edges(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + if (use_zbuf) { + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_edges( + esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + } } else { mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); @@ -3158,17 +3386,25 @@ static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval } if (ts->selectmode & SCE_SELECT_FACE) { - if (bbsel) { - changed |= edbm_backbuf_check_and_select_faces(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + if (use_zbuf) { + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_faces( + esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + } } else { mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } } - changed |= data.is_changed; + if (use_zbuf) { + if (esel->select_bitmap != NULL) { + MEM_freeN(esel->select_bitmap); + esel->select_bitmap = NULL; + } + } - EDBM_backbuf_free(); + changed |= data.is_changed; if (changed) { EDBM_selectmode_flush(vc->em); @@ -3177,6 +3413,7 @@ static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval } static bool paint_facesel_circle_select(ViewContext *vc, + wmGenericUserData *wm_userdata, const eSelectOp sel_op, const int mval[2], float rad) @@ -3184,7 +3421,6 @@ static bool paint_facesel_circle_select(ViewContext *vc, BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB)); Object *ob = vc->obact; Mesh *me = ob->data; - bool bbsel; bool changed = false; if (SEL_OP_USE_PRE_DESELECT(sel_op)) { @@ -3192,13 +3428,21 @@ static bool paint_facesel_circle_select(ViewContext *vc, changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false); } - bm_vertoffs = me->totpoly + 1; /* max index array */ + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + } - bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); - if (bbsel) { - changed |= edbm_backbuf_check_and_select_tfaces(me, sel_op); - EDBM_backbuf_free(); + { + struct EditSelectBuf_Cache *esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_circle(buffer_len, mval, (int)(rad + 1.0f)); + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op); + MEM_freeN(esel->select_bitmap); + esel->select_bitmap = NULL; + } } + if (changed) { paintface_flush_flags(vc->C, ob, SELECT); } @@ -3218,6 +3462,7 @@ static void paint_vertsel_circle_select_doSelectVert(void *userData, } } static bool paint_vertsel_circle_select(ViewContext *vc, + wmGenericUserData *wm_userdata, const eSelectOp sel_op, const int mval[2], float rad) @@ -3226,7 +3471,6 @@ static bool paint_vertsel_circle_select(ViewContext *vc, const bool use_zbuf = !XRAY_ENABLED(vc->v3d); Object *ob = vc->obact; Mesh *me = ob->data; - bool bbsel; /* CircleSelectUserData data = {NULL}; */ /* UNUSED */ bool changed = false; @@ -3238,12 +3482,19 @@ static bool paint_vertsel_circle_select(ViewContext *vc, const bool select = (sel_op != SEL_OP_SUB); if (use_zbuf) { - bm_vertoffs = me->totvert + 1; /* max index array */ + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + } + } - bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); - if (bbsel) { - changed |= edbm_backbuf_check_and_select_verts_obmode(me, sel_op); - EDBM_backbuf_free(); + if (use_zbuf) { + struct EditSelectBuf_Cache *esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_circle(buffer_len, mval, (int)(rad + 1.0f)); + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op); + MEM_freeN(esel->select_bitmap); + esel->select_bitmap = NULL; } } else { @@ -3591,27 +3842,40 @@ static bool mball_circle_select(ViewContext *vc, /** Callbacks for circle selection in Editmode */ static bool obedit_circle_select(ViewContext *vc, + wmGenericUserData *wm_userdata, const eSelectOp sel_op, const int mval[2], float rad) { + bool changed = false; BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB)); switch (vc->obedit->type) { case OB_MESH: - return mesh_circle_select(vc, sel_op, mval, rad); + changed = mesh_circle_select(vc, wm_userdata, sel_op, mval, rad); + break; case OB_CURVE: case OB_SURF: - return nurbscurve_circle_select(vc, sel_op, mval, rad); + changed = nurbscurve_circle_select(vc, sel_op, mval, rad); + break; case OB_LATTICE: - return lattice_circle_select(vc, sel_op, mval, rad); + changed = lattice_circle_select(vc, sel_op, mval, rad); + break; case OB_ARMATURE: - return armature_circle_select(vc, sel_op, mval, rad); + changed = armature_circle_select(vc, sel_op, mval, rad); + break; case OB_MBALL: - return mball_circle_select(vc, sel_op, mval, rad); + changed = mball_circle_select(vc, sel_op, mval, rad); + break; default: BLI_assert(0); - return false; + break; } + + if (changed) { + DEG_id_tag_update(vc->obact->data, ID_RECALC_SELECT); + WM_main_add_notifier(NC_GEOM | ND_SELECT, vc->obact->data); + } + return changed; } static bool object_circle_select(ViewContext *vc, @@ -3660,8 +3924,13 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) const int radius = RNA_int_get(op->ptr, "radius"); const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")}; + /* Allow each selection type to allocate their own data thats used between executions. */ + wmGesture *gesture = op->customdata; /* NULL when non-modal. */ + wmGenericUserData wm_userdata_buf = {0}; + wmGenericUserData *wm_userdata = gesture ? &gesture->user_data : &wm_userdata_buf; + const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"), - WM_gesture_is_modal_first(op->customdata)); + WM_gesture_is_modal_first(gesture)); ED_view3d_viewcontext_init(C, &vc); @@ -3670,6 +3939,9 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) if (obedit || BKE_paint_select_elem_test(obact) || (obact && (obact->mode & OB_MODE_POSE))) { view3d_operator_needs_opengl(C); + if (obedit == NULL) { + BKE_object_update_select_id(CTX_data_main(C)); + } FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, obact->type, obact->mode, ob_iter) { ED_view3d_viewcontext_init_object(&vc, ob_iter); @@ -3678,16 +3950,13 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) obedit = vc.obedit; if (obedit) { - if (obedit_circle_select(&vc, sel_op, mval, (float)radius)) { - DEG_id_tag_update(obact->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); - } + obedit_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius); } else if (BKE_paint_select_face_test(obact)) { - paint_facesel_circle_select(&vc, sel_op, mval, (float)radius); + paint_facesel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius); } else if (BKE_paint_select_vert_test(obact)) { - paint_vertsel_circle_select(&vc, sel_op, mval, (float)radius); + paint_vertsel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius); } else if (obact->mode & OB_MODE_POSE) { pose_circle_select(&vc, sel_op, mval, (float)radius); @@ -3714,6 +3983,11 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) } } + /* Otherwise this is freed by the gesture. */ + if (wm_userdata == &wm_userdata_buf) { + WM_generic_user_data_free(wm_userdata); + } + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 91313657f59..bb8c1a40a05 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -86,21 +86,6 @@ void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float UI_GetThemeColor3fv(TH_BACK, r_color); } -void ED_view3d_cursor3d_calc_mat3(const Scene *scene, float mat[3][3]) -{ - const View3DCursor *cursor = &scene->cursor; - BKE_scene_cursor_rot_to_mat3(cursor, mat); -} - -void ED_view3d_cursor3d_calc_mat4(const Scene *scene, float mat[4][4]) -{ - const View3DCursor *cursor = &scene->cursor; - float mat3[3][3]; - BKE_scene_cursor_rot_to_mat3(cursor, mat3); - copy_m4_m3(mat, mat3); - copy_v3_v3(mat[3], cursor->location); -} - Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d) { /* establish the camera object, diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 2454358b687..5865efa0ffa 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -428,7 +428,7 @@ void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *ar) * can use them without redrawing first */ Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); - ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL); + ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL, false); } } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 81405b55ac2..c3acd604ee1 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -4835,6 +4835,7 @@ static void initNormalRotation(TransInfo *t) BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); BMesh *bm = em->bm; + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); storeCustomLNorValue(tc, bm); @@ -4917,8 +4918,7 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3]) } else if (t->spacetype == SPACE_NODE) { r_snap[0] = 0.0f; - r_snap[1] = ED_node_grid_size(); - r_snap[2] = ED_node_grid_size(); + r_snap[1] = r_snap[2] = ED_node_grid_size(); } else if (t->spacetype == SPACE_GRAPH) { r_snap[0] = 0.0f; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 50fc1a276b9..b0f720bfdf7 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -383,6 +383,30 @@ typedef struct BoneInitData { float zwidth; } BoneInitData; +typedef struct PoseInitData_Mirror { + /** Points to the bone which this info is initialized & restored to. + * A NULL value is used to terminate the array. */ + struct bPoseChannel *pchan; + struct { + float loc[3]; + float size[3]; + union { + float eul[3]; + float quat[4]; + float axis_angle[4]; + }; + float curve_in_x; + float curve_out_x; + float roll1; + float roll2; + } orig; + /** + * An extra offset to apply after mirroring. + * Use with #POSE_MIRROR_RELATIVE. + */ + float offset_mtx[4][4]; +} PoseInitData_Mirror; + typedef struct TransData { /** Distance needed to affect element (for Proportionnal Editing). */ float dist; @@ -501,7 +525,7 @@ typedef struct TransDataContainer { struct Object *obedit; /** - * Use when #T_LOCAL_MATRIX is set. + * Store matrix, this avoids having to have duplicate check all over * Typically: 'obedit->obmat' or 'poseobj->obmat', but may be used elsewhere too. */ bool use_local_mat; @@ -715,10 +739,8 @@ enum { T_CURSOR = 1 << 5, /** Transform points, having no rotation/scale. */ T_POINTS = 1 << 6, - /** - * Apply matrix #TransDataContainer.matrix, this avoids having to have duplicate check all over - * that happen to apply to specific modes (edit & pose for eg). */ - T_LOCAL_MATRIX = 1 << 7, + + /* empty slot - (1 << 7) */ /** restrictions flags */ T_NO_CONSTRAINT = 1 << 8, @@ -892,6 +914,7 @@ void flushTransSeq(TransInfo *t); void flushTransTracking(TransInfo *t); void flushTransMasking(TransInfo *t); void flushTransPaintCurve(TransInfo *t); +void restoreMirrorPoseBones(TransDataContainer *tc); void restoreBones(TransDataContainer *tc); /*********************** transform_gizmo.c ********** */ diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 6c1da5ae825..4037fab2b68 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -198,7 +198,10 @@ void sort_trans_data_dist(TransInfo *t) } } -static void sort_trans_data_container(TransDataContainer *tc) +/** + * Make #TD_SELECTED first in the array. + */ +static void sort_trans_data_selected_first_container(TransDataContainer *tc) { TransData *sel, *unsel; TransData temp; @@ -225,10 +228,10 @@ static void sort_trans_data_container(TransDataContainer *tc) unsel++; } } -static void sort_trans_data(TransInfo *t) +static void sort_trans_data_selected_first(TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { - sort_trans_data_container(tc); + sort_trans_data_selected_first_container(tc); } } @@ -1201,6 +1204,74 @@ static short pose_grab_with_ik(Main *bmain, Object *ob) return (tot_ik) ? 1 : 0; } +static void pose_mirror_info_init(PoseInitData_Mirror *pid, + bPoseChannel *pchan, + bPoseChannel *pchan_orig, + bool is_mirror_relative) +{ + pid->pchan = pchan; + copy_v3_v3(pid->orig.loc, pchan->loc); + copy_v3_v3(pid->orig.size, pchan->size); + pid->orig.curve_in_x = pchan->curve_in_x; + pid->orig.curve_out_x = pchan->curve_out_x; + pid->orig.roll1 = pchan->roll1; + pid->orig.roll2 = pchan->roll2; + + if (pchan->rotmode > 0) { + copy_v3_v3(pid->orig.eul, pchan->eul); + } + else if (pchan->rotmode == ROT_MODE_AXISANGLE) { + copy_v3_v3(pid->orig.axis_angle, pchan->rotAxis); + pid->orig.axis_angle[3] = pchan->rotAngle; + } + else { + copy_qt_qt(pid->orig.quat, pchan->quat); + } + + if (is_mirror_relative) { + float pchan_mtx[4][4]; + float pchan_mtx_mirror[4][4]; + + float flip_mtx[4][4]; + unit_m4(flip_mtx); + flip_mtx[0][0] = -1; + + BKE_pchan_to_mat4(pchan_orig, pchan_mtx_mirror); + BKE_pchan_to_mat4(pchan, pchan_mtx); + + mul_m4_m4m4(pchan_mtx_mirror, pchan_mtx_mirror, flip_mtx); + mul_m4_m4m4(pchan_mtx_mirror, flip_mtx, pchan_mtx_mirror); + + invert_m4(pchan_mtx_mirror); + mul_m4_m4m4(pid->offset_mtx, pchan_mtx, pchan_mtx_mirror); + } + else { + unit_m4(pid->offset_mtx); + } +} + +static void pose_mirror_info_restore(const PoseInitData_Mirror *pid) +{ + bPoseChannel *pchan = pid->pchan; + copy_v3_v3(pchan->loc, pid->orig.loc); + copy_v3_v3(pchan->size, pid->orig.size); + pchan->curve_in_x = pid->orig.curve_in_x; + pchan->curve_out_x = pid->orig.curve_out_x; + pchan->roll1 = pid->orig.roll1; + pchan->roll2 = pid->orig.roll2; + + if (pchan->rotmode > 0) { + copy_v3_v3(pchan->eul, pid->orig.eul); + } + else if (pchan->rotmode == ROT_MODE_AXISANGLE) { + copy_v3_v3(pchan->rotAxis, pid->orig.axis_angle); + pchan->rotAngle = pid->orig.axis_angle[3]; + } + else { + copy_qt_qt(pchan->quat, pid->orig.quat); + } +} + /** * When objects array is NULL, use 't->data_container' as is. */ @@ -1215,16 +1286,19 @@ static void createTransPose(TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { Object *ob = tc->poseobj; + bPose *pose = ob->pose; bArmature *arm; short ik_on = 0; /* check validity of state */ arm = BKE_armature_from_object(tc->poseobj); - if ((arm == NULL) || (ob->pose == NULL)) { + if ((arm == NULL) || (pose == NULL)) { continue; } + const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0); + /* set flags and count total */ tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate); if (tc->data_len == 0) { @@ -1240,13 +1314,32 @@ static void createTransPose(TransInfo *t) } /* do we need to add temporal IK chains? */ - if ((arm->flag & ARM_AUTO_IK) && t->mode == TFM_TRANSLATION) { + if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) { ik_on = pose_grab_with_ik(bmain, ob); if (ik_on) { t->flag |= T_AUTOIK; has_translate_rotate[0] = true; } } + + if (mirror) { + int total_mirrored = 0; + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if ((pchan->bone->flag & BONE_TRANSFORM) && + BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) { + total_mirrored++; + } + } + + PoseInitData_Mirror *pid = MEM_mallocN((total_mirrored + 1) * sizeof(PoseInitData_Mirror), + "PoseInitData_Mirror"); + + /* Trick to terminate iteration. */ + pid[total_mirrored].pchan = NULL; + + tc->custom.type.data = pid; + tc->custom.type.use_free = true; + } } /* if there are no translatable bones, do rotation */ @@ -1269,6 +1362,17 @@ static void createTransPose(TransInfo *t) short ik_on = 0; int i; + PoseInitData_Mirror *pid = tc->custom.type.data; + int pid_index = 0; + bPose *pose = ob->pose; + + if (pose == NULL) { + continue; + } + + const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0); + const bool is_mirror_relative = ((pose->flag & POSE_MIRROR_RELATIVE) != 0); + tc->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */ /* init trans data */ @@ -1285,6 +1389,15 @@ static void createTransPose(TransInfo *t) for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->bone->flag & BONE_TRANSFORM) { add_pose_transdata(t, pchan, ob, tc, td); + + if (mirror) { + bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name); + if (pchan_mirror) { + pose_mirror_info_init(&pid[pid_index], pchan_mirror, pchan, is_mirror_relative); + pid_index++; + } + } + td++; } } @@ -1304,6 +1417,19 @@ static void createTransPose(TransInfo *t) t->flag &= ~T_PROP_EDIT_ALL; } +void restoreMirrorPoseBones(TransDataContainer *tc) +{ + bPose *pose = tc->poseobj->pose; + + if (!(pose->flag & POSE_MIRROR_EDIT)) { + return; + } + + for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) { + pose_mirror_info_restore(pid); + } +} + void restoreBones(TransDataContainer *tc) { bArmature *arm; @@ -9253,7 +9379,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && t->flag & T_PROP_EDIT) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, 1); sort_trans_data_dist(t); } @@ -9267,7 +9393,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, 1); sort_trans_data_dist(t); } @@ -9281,7 +9407,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, true); sort_trans_data_dist(t); } @@ -9304,7 +9430,7 @@ void createTransData(bContext *C, TransInfo *t) t->flag |= T_EDIT; if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, 1); sort_trans_data_dist(t); } @@ -9321,7 +9447,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); /* don't do that, distance has been set in createTransActionData already */ // set_prop_dist(t, false); sort_trans_data_dist(t); @@ -9351,7 +9477,7 @@ void createTransData(bContext *C, TransInfo *t) if (t->data_len_all && (t->flag & T_PROP_EDIT)) { /* makes selected become first in array */ - sort_trans_data(t); + sort_trans_data_selected_first(t); /* don't do that, distance has been set in createTransGraphEditData already */ set_prop_dist(t, false); @@ -9367,7 +9493,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, 1); sort_trans_data_dist(t); } @@ -9386,7 +9512,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, true); sort_trans_data_dist(t); } @@ -9426,21 +9552,30 @@ void createTransData(bContext *C, TransInfo *t) t->flag |= T_EDIT | T_POINTS; - if (t->data_len_all && t->flag & T_PROP_EDIT) { - if (ELEM(t->obedit_type, OB_CURVE, OB_MESH)) { - sort_trans_data(t); // makes selected become first in array - if ((t->obedit_type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) { - /* already calculated by editmesh_set_connectivity_distance */ + if (t->data_len_all) { + if (t->flag & T_PROP_EDIT) { + if (ELEM(t->obedit_type, OB_CURVE, OB_MESH)) { + sort_trans_data_selected_first(t); + if ((t->obedit_type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) { + /* already calculated by editmesh_set_connectivity_distance */ + } + else { + set_prop_dist(t, 0); + } + sort_trans_data_dist(t); } else { - set_prop_dist(t, 0); + sort_trans_data_selected_first(t); + set_prop_dist(t, 1); + sort_trans_data_dist(t); } - sort_trans_data_dist(t); } else { - sort_trans_data(t); // makes selected become first in array - set_prop_dist(t, 1); - sort_trans_data_dist(t); + if (ELEM(t->obedit_type, OB_CURVE)) { + /* Needed because bezier handles can be partially selected + * and are still added into transform data. */ + sort_trans_data_selected_first(t); + } } } @@ -9494,7 +9629,7 @@ void createTransData(bContext *C, TransInfo *t) t->flag |= T_POINTS; if (t->data_len_all && t->flag & T_PROP_EDIT) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, 1); sort_trans_data_dist(t); } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 8ddc5461e9a..758551be0b5 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -781,6 +781,49 @@ static void recalcData_spaceclip(TransInfo *t) } } +/** + * if pose bone (partial) selected, copy data. + * context; posemode armature, with mirror editing enabled. + * + * \param pid: Optional, apply relative transform when set. + */ +static void pose_transform_mirror_update(Object *ob, PoseInitData_Mirror *pid) +{ + float flip_mtx[4][4]; + unit_m4(flip_mtx); + flip_mtx[0][0] = -1; + + for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig; + pchan_orig = pchan_orig->next) { + /* no layer check, correct mirror is more important */ + if (pchan_orig->bone->flag & BONE_TRANSFORM) { + bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name); + + if (pchan) { + /* also do bbone scaling */ + pchan->bone->xwidth = pchan_orig->bone->xwidth; + pchan->bone->zwidth = pchan_orig->bone->zwidth; + + /* we assume X-axis flipping for now */ + pchan->curve_in_x = pchan_orig->curve_in_x * -1; + pchan->curve_out_x = pchan_orig->curve_out_x * -1; + pchan->roll1 = pchan_orig->roll1 * -1; // XXX? + pchan->roll2 = pchan_orig->roll2 * -1; // XXX? + + float pchan_mtx_final[4][4]; + BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final); + mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx); + mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final); + if (pid) { + mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final); + pid++; + } + BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false); + } + } + } +} + /* helper for recalcData() - for object transforms, typically in the 3D view */ static void recalcData_objects(TransInfo *t) { @@ -975,12 +1018,22 @@ static void recalcData_objects(TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { Object *ob = tc->poseobj; bArmature *arm = ob->data; - if (arm->flag & ARM_MIRROR_EDIT) { - if (t->state != TRANS_CANCEL) { - ED_armature_edit_transform_mirror_update(ob); + if (ob->mode == OB_MODE_EDIT) { + if (arm->flag & ARM_MIRROR_EDIT) { + if (t->state != TRANS_CANCEL) { + ED_armature_edit_transform_mirror_update(ob); + } + else { + restoreBones(tc); + } } - else { - restoreBones(tc); + } + else if (ob->mode == OB_MODE_POSE) { + /* actually support TFM_BONESIZE in posemode as well */ + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + bPose *pose = ob->pose; + if (arm->flag & ARM_MIRROR_EDIT || pose->flag & POSE_MIRROR_EDIT) { + pose_transform_mirror_update(ob, NULL); } } } @@ -991,6 +1044,20 @@ static void recalcData_objects(TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { Object *ob = tc->poseobj; bArmature *arm = ob->data; + bPose *pose = ob->pose; + + if (pose->flag & POSE_MIRROR_EDIT) { + if (t->state != TRANS_CANCEL) { + PoseInitData_Mirror *pid = NULL; + if (pose->flag & POSE_MIRROR_RELATIVE) { + pid = tc->custom.type.data; + } + pose_transform_mirror_update(ob, pid); + } + else { + restoreMirrorPoseBones(tc); + } + } /* if animtimer is running, and the object already has animation data, * check if the auto-record feature means that we should record 'samples' @@ -1309,7 +1376,9 @@ void initTransDataContainers_FromObjectData(TransInfo *t, BLI_assert((t->flag & T_2D_EDIT) == 0); copy_m4_m4(tc->mat, objects[i]->obmat); copy_m3_m4(tc->mat3, tc->mat); - invert_m4_m4(tc->imat, tc->mat); + /* for non-invertible scale matrices, invert_m4_m4_fallback() + * can still provide a valid pivot */ + invert_m4_m4_fallback(tc->imat, tc->mat); invert_m3_m3(tc->imat3, tc->mat3); normalize_m3_m3(tc->mat3_unit, tc->mat3); } diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 50610f1b3da..e43379dc358 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -703,7 +703,7 @@ void ED_transform_calc_orientation_from_type_ex(const bContext *C, break; } case V3D_ORIENT_CURSOR: { - ED_view3d_cursor3d_calc_mat3(scene, r_mat); + BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat); ok = true; break; } @@ -1762,6 +1762,15 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) } } MAN_ITER_AXES_END; + + /* Ensure rotate disks don't overlap scale arrows, especially in ortho view. */ + float rotate_select_bias = 0.0f; + if ((ggd->twtype & V3D_GIZMO_SHOW_OBJECT_SCALE) && ggd->twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) { + rotate_select_bias = -2.0f; + } + for (int i = MAN_AXIS_RANGE_ROT_START; i < MAN_AXIS_RANGE_ROT_END; i++) { + ggd->gizmos[i]->select_bias = rotate_select_bias; + } } static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C, diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 8606cd19c96..cdd0896ab66 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -1170,7 +1170,7 @@ static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; RNA_def_float_rotation( ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index e16579aba64..70bb2bf98a6 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -485,7 +485,7 @@ void initTransformOrientation(bContext *C, TransInfo *t) break; case V3D_ORIENT_CURSOR: { BLI_strncpy(t->spacename, IFACE_("cursor"), sizeof(t->spacename)); - ED_view3d_cursor3d_calc_mat3(t->scene, t->spacemtx); + BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx); break; } case V3D_ORIENT_CUSTOM_MATRIX: diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 49b5cada04a..99143cd71f9 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -392,6 +392,15 @@ static bool ed_undo_redo_poll(bContext *C) WM_operator_check_ui_enabled(C, last_op->type->name)); } +static bool ed_undo_poll(bContext *C) +{ + if (!ed_undo_is_init_and_screenactive_poll(C)) { + return false; + } + UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack; + return (undo_stack->step_active != NULL) && (undo_stack->step_active->prev != NULL); +} + void ED_OT_undo(wmOperatorType *ot) { /* identifiers */ @@ -401,7 +410,7 @@ void ED_OT_undo(wmOperatorType *ot) /* api callbacks */ ot->exec = ed_undo_exec; - ot->poll = ed_undo_is_init_and_screenactive_poll; + ot->poll = ed_undo_poll; } void ED_OT_undo_push(wmOperatorType *ot) @@ -426,6 +435,15 @@ void ED_OT_undo_push(wmOperatorType *ot) ""); } +static bool ed_redo_poll(bContext *C) +{ + if (!ed_undo_is_init_and_screenactive_poll(C)) { + return false; + } + UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack; + return (undo_stack->step_active != NULL) && (undo_stack->step_active->next != NULL); +} + void ED_OT_redo(wmOperatorType *ot) { /* identifiers */ @@ -435,7 +453,7 @@ void ED_OT_redo(wmOperatorType *ot) /* api callbacks */ ot->exec = ed_redo_exec; - ot->poll = ed_undo_is_init_and_screenactive_poll; + ot->poll = ed_redo_poll; } void ED_OT_undo_redo(wmOperatorType *ot) @@ -569,7 +587,7 @@ static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem) item_tmp.identifier = us->name; item_tmp.name = IFACE_(us->name); if (us == wm->undo_stack->step_active) { - item_tmp.icon = ICON_HIDE_OFF; + item_tmp.icon = ICON_LAYER_ACTIVE; } else { item_tmp.icon = ICON_NONE; @@ -633,6 +651,16 @@ static int undo_history_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } +static bool undo_history_poll(bContext *C) +{ + if (!ed_undo_is_init_and_screenactive_poll(C)) { + return false; + } + UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack; + /* more than just original state entry */ + return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1; +} + void ED_OT_undo_history(wmOperatorType *ot) { /* identifiers */ @@ -643,7 +671,7 @@ void ED_OT_undo_history(wmOperatorType *ot) /* api callbacks */ ot->invoke = undo_history_invoke; ot->exec = undo_history_exec; - ot->poll = ed_undo_is_init_and_screenactive_poll; + ot->poll = undo_history_poll; RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX); } diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 3b49784d5eb..c09237d825d 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -41,6 +41,7 @@ set(SRC ed_util.c gizmo_utils.c numinput.c + select_buffer_utils.c select_utils.c # general includes @@ -79,11 +80,13 @@ set(SRC ../include/ED_screen.h ../include/ED_screen_types.h ../include/ED_sculpt.h + ../include/ED_select_buffer_utils.h ../include/ED_select_utils.h ../include/ED_sequencer.h ../include/ED_sound.h ../include/ED_space_api.h ../include/ED_text.h + ../include/ED_time_scrub_ui.h ../include/ED_transform.h ../include/ED_transform_snap_object_context.h ../include/ED_transverts.h diff --git a/source/blender/editors/util/select_buffer_utils.c b/source/blender/editors/util/select_buffer_utils.c new file mode 100644 index 00000000000..130f6819e34 --- /dev/null +++ b/source/blender/editors/util/select_buffer_utils.c @@ -0,0 +1,303 @@ +/* + * 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) 2008 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edutil + * + * Generic utilities for handling buffer selection where selection ID's are drawn onto + * an off screen buffer. + * + * All coordinates are relative to the current region. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap.h" +#include "BLI_bitmap_draw_2d.h" +#include "BLI_rect.h" +#include "BLI_utildefines.h" + +#include "ED_select_buffer_utils.h" + +/* Only for #ED_view3d_select_id_read, + * note that this file shouldn't have 3D view specific logic in it, we could have a more general + * way to read from selection buffers that doesn't depend on the view3d API. */ +#include "ED_view3d.h" + +/* -------------------------------------------------------------------- */ +/** \name Select Bitmap from ID's + * + * Given a buffer of select ID's, fill in a booleans (true/false) per index. + * #BLI_bitmap is used for memory effeciency. + * + * \{ */ + +/** + * \param bitmap_len: Number of indices in the selection id buffer. + * \param rect: The rectangle to sample indices from (min/max inclusive). + * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. + */ +uint *ED_select_buffer_bitmap_from_rect(const uint bitmap_len, const rcti *rect) +{ + uint buf_len; + const uint *buf = ED_view3d_select_id_read( + rect->xmin, rect->ymin, rect->xmax, rect->ymax, &buf_len); + if (buf == NULL) { + return NULL; + } + + const uint *buf_iter = buf; + + BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__); + + while (buf_len--) { + const uint index = *buf_iter - 1; + if (index < bitmap_len) { + BLI_BITMAP_ENABLE(bitmap_buf, index); + } + buf_iter++; + } + MEM_freeN((void *)buf); + return bitmap_buf; +} + +/** + * \param bitmap_len: Number of indices in the selection id buffer. + * \param center: Circle center. + * \param radius: Circle radius. + * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. + */ +uint *ED_select_buffer_bitmap_from_circle(const uint bitmap_len, + const int center[2], + const int radius) +{ + if (bitmap_len == 0) { + return NULL; + } + + const int xmin = center[0] - radius; + const int xmax = center[0] + radius; + const int ymin = center[1] - radius; + const int ymax = center[1] + radius; + + const uint *buf = ED_view3d_select_id_read(xmin, ymin, xmax, ymax, NULL); + if (buf == NULL) { + return NULL; + } + + const uint *buf_iter = buf; + + BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__); + const int radius_sq = radius * radius; + for (int yc = -radius; yc <= radius; yc++) { + for (int xc = -radius; xc <= radius; xc++, buf_iter++) { + if (xc * xc + yc * yc < radius_sq) { + /* Intentionally wrap to max value if this is zero. */ + const uint index = *buf_iter - 1; + if (index < bitmap_len) { + BLI_BITMAP_ENABLE(bitmap_buf, index); + } + } + } + } + MEM_freeN((void *)buf); + return bitmap_buf; +} + +struct PolyMaskData { + BLI_bitmap *px; + int width; +}; + +static void ed_select_buffer_mask_px_cb(int x, int x_end, int y, void *user_data) +{ + struct PolyMaskData *data = user_data; + BLI_bitmap *px = data->px; + int i = (y * data->width) + x; + do { + BLI_BITMAP_ENABLE(px, i); + i++; + } while (++x != x_end); +} + +/** + * \param bitmap_len: Number of indices in the selection id buffer. + * \param center: Circle center. + * \param radius: Circle radius. + * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. + */ +uint *ED_select_buffer_bitmap_from_poly(const uint bitmap_len, + const int poly[][2], + const int poly_len, + const rcti *rect) + +{ + if (bitmap_len == 0) { + return NULL; + } + + struct PolyMaskData poly_mask_data; + uint buf_len; + const uint *buf = ED_view3d_select_id_read( + rect->xmin, rect->ymin, rect->xmax, rect->ymax, &buf_len); + if (buf == NULL) { + return NULL; + } + + BLI_bitmap *buf_mask = BLI_BITMAP_NEW(buf_len, __func__); + poly_mask_data.px = buf_mask; + poly_mask_data.width = (rect->xmax - rect->xmin) + 1; + + BLI_bitmap_draw_2d_poly_v2i_n(rect->xmin, + rect->ymin, + rect->xmax + 1, + rect->ymax + 1, + poly, + poly_len, + ed_select_buffer_mask_px_cb, + &poly_mask_data); + + /* Build selection lookup. */ + const uint *buf_iter = buf; + BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__); + int i = 0; + while (buf_len--) { + const uint index = *buf_iter - 1; + if (index < bitmap_len && BLI_BITMAP_TEST(buf_mask, i)) { + BLI_BITMAP_ENABLE(bitmap_buf, index); + } + buf_iter++; + i++; + } + MEM_freeN((void *)buf); + MEM_freeN(buf_mask); + + return bitmap_buf; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Find Single Select ID's + * + * Given a buffer of select ID's, find the a single select id. + * + * \{ */ + +/** + * Samples a single pixel. + */ +uint ED_select_buffer_sample_point(const int center[2]) +{ + uint buf_len; + uint *buf = ED_view3d_select_id_read(center[0], center[1], center[0], center[1], &buf_len); + BLI_assert(0 != buf_len); + uint ret = buf[0]; + MEM_freeN(buf); + return ret; +} + +/** + * Find the selection id closest to \a center. + * \param dist[in,out]: Use to initalize the distance, + * when found, this value is set to the distance of the selection thats returned. + */ +uint ED_select_buffer_find_nearest_to_point(const int center[2], + const uint id_min, + const uint id_max, + uint *dist) +{ + /* Smart function to sample a rect spiralling outside, nice for selection ID. */ + + /* Create region around center (typically the mouse cursor). + * This must be square and have an odd width, + * the spiraling algorithm does not work with arbitrary rectangles. */ + rcti rect; + BLI_rcti_init_pt_radius(&rect, center, *dist); + rect.xmax += 1; + rect.ymax += 1; + + int width = BLI_rcti_size_x(&rect); + int height = width; + BLI_assert(width == height); + + /* Read from selection framebuffer. */ + + uint buf_len; + const uint *buf = ED_view3d_select_id_read_rect(&rect, &buf_len); + BLI_assert(width * height == buf_len); + + /* Spiral, starting from center of buffer. */ + int spiral_offset = height * (int)(width / 2) + (height / 2); + int spiral_direction = 0; + + uint index = 0; + + for (int nr = 1; nr <= height; nr++) { + for (int a = 0; a < 2; a++) { + for (int b = 0; b < nr; b++) { + /* Find hit within the specified range. */ + uint hit_id = buf[spiral_offset]; + + if (hit_id && hit_id >= id_min && hit_id < id_max) { + /* Get x/y from spiral offset. */ + int hit_x = spiral_offset % width; + int hit_y = spiral_offset / width; + + int center_x = width / 2; + int center_y = height / 2; + + /* Manhatten distance in keeping with other screen-based selection. */ + *dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y)); + + /* Indices start at 1 here. */ + index = (hit_id - id_min) + 1; + goto exit; + } + + /* Next spiral step. */ + if (spiral_direction == 0) { + spiral_offset += 1; /* right */ + } + else if (spiral_direction == 1) { + spiral_offset -= width; /* down */ + } + else if (spiral_direction == 2) { + spiral_offset -= 1; /* left */ + } + else { + spiral_offset += width; /* up */ + } + + /* Stop if we are outside the buffer. */ + if (spiral_offset < 0 || spiral_offset >= buf_len) { + goto exit; + } + } + + spiral_direction = (spiral_direction + 1) % 4; + } + } + +exit: + MEM_freeN((void *)buf); + return index; +} + +/** \} */ diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 804b9c22104..7f9b90f4496 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -170,6 +170,7 @@ static void uvedit_get_batches(Object *ob, const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0; const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0; + DRW_mesh_batch_cache_validate(ob->data); *edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data); *verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data); @@ -206,6 +207,7 @@ static void draw_uvs_shadow(SpaceImage *UNUSED(sima), float col[4]; UI_GetThemeColor4fv(TH_UV_SHADOW, col); + DRW_mesh_batch_cache_validate(me); GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me); DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false); @@ -228,6 +230,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph) return; } + DRW_mesh_batch_cache_validate(me); GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me); DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false); @@ -243,6 +246,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph) bool prev_ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1)); GPU_matrix_bind(geom->interface); + GPU_batch_bind(geom); /* TODO(fclem): If drawcall count becomes a problem in the future * we can use multi draw indirect drawcalls for this. @@ -251,7 +255,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph) bool ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1)); if (ma_match != prev_ma_match) { if (ma_match == false) { - GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false); + GPU_batch_draw_advanced(geom, draw_start, idx - draw_start, 0, 0); } else { draw_start = idx; @@ -261,7 +265,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph) prev_ma_match = ma_match; } if (prev_ma_match == true) { - GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false); + GPU_batch_draw_advanced(geom, draw_start, idx - draw_start, 0, 0); } GPU_batch_program_use_end(geom); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 85393925802..717bc347cf7 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -386,6 +386,10 @@ static ParamHandle *construct_param_handle_multi(Scene *scene, const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + continue; + } + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || |