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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/CMakeLists.txt1
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c10
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c51
-rw-r--r--source/blender/editors/animation/anim_filter.c4
-rw-r--r--source/blender/editors/animation/anim_markers.c4
-rw-r--r--source/blender/editors/animation/drivers.c3
-rw-r--r--source/blender/editors/animation/keyframes_general.c3
-rw-r--r--source/blender/editors/animation/keyframing.c11
-rw-r--r--source/blender/editors/animation/time_scrub_ui.c214
-rw-r--r--source/blender/editors/armature/armature_intern.h2
-rw-r--r--source/blender/editors/armature/armature_naming.c10
-rw-r--r--source/blender/editors/armature/armature_ops.c2
-rw-r--r--source/blender/editors/armature/armature_relations.c37
-rw-r--r--source/blender/editors/armature/armature_select.c8
-rw-r--r--source/blender/editors/armature/armature_utils.c6
-rw-r--r--source/blender/editors/armature/pose_edit.c34
-rw-r--r--source/blender/editors/armature/pose_lib.c1
-rw-r--r--source/blender/editors/armature/pose_slide.c255
-rw-r--r--source/blender/editors/armature/pose_transform.c338
-rw-r--r--source/blender/editors/armature/pose_utils.c1
-rw-r--r--source/blender/editors/curve/editcurve.c405
-rw-r--r--source/blender/editors/curve/editfont.c4
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt4
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c2
-rw-r--r--source/blender/editors/include/ED_anim_api.h15
-rw-r--r--source/blender/editors/include/ED_image.h5
-rw-r--r--source/blender/editors/include/ED_mesh.h52
-rw-r--r--source/blender/editors/include/ED_screen.h17
-rw-r--r--source/blender/editors/include/ED_select_buffer_utils.h43
-rw-r--r--source/blender/editors/include/ED_time_scrub_ui.h43
-rw-r--r--source/blender/editors/include/ED_view3d.h24
-rw-r--r--source/blender/editors/include/UI_icons.h116
-rw-r--r--source/blender/editors/include/UI_interface.h49
-rw-r--r--source/blender/editors/include/UI_interface_icons.h25
-rw-r--r--source/blender/editors/include/UI_resources.h10
-rw-r--r--source/blender/editors/include/UI_view2d.h50
-rw-r--r--source/blender/editors/interface/interface.c39
-rw-r--r--source/blender/editors/interface/interface_anim.c5
-rw-r--r--source/blender/editors/interface/interface_context_menu.c159
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c42
-rw-r--r--source/blender/editors/interface/interface_icons.c549
-rw-r--r--source/blender/editors/interface/interface_intern.h7
-rw-r--r--source/blender/editors/interface/interface_layout.c145
-rw-r--r--source/blender/editors/interface/interface_panel.c244
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.c2
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c25
-rw-r--r--source/blender/editors/interface/interface_region_popover.c10
-rw-r--r--source/blender/editors/interface/interface_region_popup.c8
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c4
-rw-r--r--source/blender/editors/interface/interface_templates.c46
-rw-r--r--source/blender/editors/interface/interface_widgets.c54
-rw-r--r--source/blender/editors/interface/resources.c42
-rw-r--r--source/blender/editors/interface/view2d.c164
-rw-r--r--source/blender/editors/interface/view2d_draw.c72
-rw-r--r--source/blender/editors/interface/view2d_ops.c4
-rw-r--r--source/blender/editors/io/io_cache.c2
-rw-r--r--source/blender/editors/mask/mask_ops.c8
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt1
-rw-r--r--source/blender/editors/mesh/editface.c68
-rw-r--r--source/blender/editors/mesh/editmesh_add_gizmo.c3
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c3
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c6
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c4
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c6
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c69
-rw-r--r--source/blender/editors/mesh/editmesh_path.c83
-rw-r--r--source/blender/editors/mesh/editmesh_select.c648
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c47
-rw-r--r--source/blender/editors/mesh/mesh_ops.c6
-rw-r--r--source/blender/editors/mesh/meshtools.c17
-rw-r--r--source/blender/editors/metaball/mball_edit.c2
-rw-r--r--source/blender/editors/object/object_add.c217
-rw-r--r--source/blender/editors/object/object_bake_api.c26
-rw-r--r--source/blender/editors/object/object_constraint.c45
-rw-r--r--source/blender/editors/object/object_edit.c5
-rw-r--r--source/blender/editors/object/object_modifier.c2
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c34
-rw-r--r--source/blender/editors/render/render_internal.c49
-rw-r--r--source/blender/editors/render/render_opengl.c36
-rw-r--r--source/blender/editors/render/render_preview.c21
-rw-r--r--source/blender/editors/render/render_shading.c6
-rw-r--r--source/blender/editors/render/render_update.c7
-rw-r--r--source/blender/editors/screen/area.c179
-rw-r--r--source/blender/editors/screen/screen_context.c59
-rw-r--r--source/blender/editors/screen/screen_edit.c18
-rw-r--r--source/blender/editors/screen/screen_ops.c205
-rw-r--r--source/blender/editors/screen/workspace_edit.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c3
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c21
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_undo.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c20
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c2
-rw-r--r--source/blender/editors/sound/sound_ops.c2
-rw-r--r--source/blender/editors/space_action/action_data.c6
-rw-r--r--source/blender/editors/space_action/action_draw.c139
-rw-r--r--source/blender/editors/space_action/action_edit.c15
-rw-r--r--source/blender/editors/space_action/action_select.c25
-rw-r--r--source/blender/editors/space_action/space_action.c26
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c4
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c5
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c108
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c3
-rw-r--r--source/blender/editors/space_clip/clip_intern.h2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c8
-rw-r--r--source/blender/editors/space_clip/space_clip.c48
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c8
-rw-r--r--source/blender/editors/space_file/file_draw.c2
-rw-r--r--source/blender/editors/space_file/file_ops.c5
-rw-r--r--source/blender/editors/space_file/fsmenu.c161
-rw-r--r--source/blender/editors/space_file/fsmenu.h2
-rw-r--r--source/blender/editors/space_file/space_file.c12
-rw-r--r--source/blender/editors/space_graph/graph_draw.c48
-rw-r--r--source/blender/editors/space_graph/graph_edit.c16
-rw-r--r--source/blender/editors/space_graph/graph_select.c2
-rw-r--r--source/blender/editors/space_graph/space_graph.c45
-rw-r--r--source/blender/editors/space_image/image_buttons.c560
-rw-r--r--source/blender/editors/space_image/image_intern.h1
-rw-r--r--source/blender/editors/space_image/image_ops.c619
-rw-r--r--source/blender/editors/space_image/space_image.c20
-rw-r--r--source/blender/editors/space_info/info_ops.c12
-rw-r--r--source/blender/editors/space_nla/nla_channels.c15
-rw-r--r--source/blender/editors/space_nla/nla_draw.c96
-rw-r--r--source/blender/editors/space_nla/nla_edit.c14
-rw-r--r--source/blender/editors/space_nla/nla_select.c12
-rw-r--r--source/blender/editors/space_nla/space_nla.c24
-rw-r--r--source/blender/editors/space_node/drawnode.c17
-rw-r--r--source/blender/editors/space_node/node_add.c2
-rw-r--r--source/blender/editors/space_node/node_edit.c9
-rw-r--r--source/blender/editors/space_node/node_select.c198
-rw-r--r--source/blender/editors/space_node/space_node.c3
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c24
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c1653
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c9
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h9
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c31
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c12
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c39
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c10
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c45
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c2
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c9
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c6
-rw-r--r--source/blender/editors/space_text/text_draw.c8
-rw-r--r--source/blender/editors/space_text/text_ops.c8
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c7
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c2
-rw-r--r--source/blender/editors/space_userpref/userpref_ops.c2
-rw-r--r--source/blender/editors/space_view3d/drawobject.c231
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c114
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c174
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c161
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_camera.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h7
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c608
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c15
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c2
-rw-r--r--source/blender/editors/transform/transform.c4
-rw-r--r--source/blender/editors/transform/transform.h33
-rw-r--r--source/blender/editors/transform/transform_conversions.c183
-rw-r--r--source/blender/editors/transform/transform_generics.c81
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c11
-rw-r--r--source/blender/editors/transform/transform_ops.c2
-rw-r--r--source/blender/editors/transform/transform_orientations.c2
-rw-r--r--source/blender/editors/undo/ed_undo.c36
-rw-r--r--source/blender/editors/util/CMakeLists.txt3
-rw-r--r--source/blender/editors/util/select_buffer_utils.c303
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c8
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c4
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(&params, sizex, sizey, scene->r.xasp, scene->r.yasp);
BKE_camera_params_compute_matrix(&params);
- 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)) ||