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/drivers.c8
-rw-r--r--source/blender/editors/animation/keyframes_edit.c74
-rw-r--r--source/blender/editors/animation/keyframing.c3
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c30
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c60
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h1
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c46
-rw-r--r--source/blender/editors/include/ED_fileselect.h2
-rw-r--r--source/blender/editors/include/ED_gpencil.h2
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h34
-rw-r--r--source/blender/editors/include/ED_mask.h2
-rw-r--r--source/blender/editors/include/UI_interface.h12
-rw-r--r--source/blender/editors/interface/interface.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c28
-rw-r--r--source/blender/editors/interface/interface_templates.c12
-rw-r--r--source/blender/editors/mask/mask_editaction.c30
-rw-r--r--source/blender/editors/mesh/editface.c3
-rw-r--r--source/blender/editors/object/object_constraint.c76
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/space_action/action_intern.h2
-rw-r--r--source/blender/editors/space_action/action_ops.c10
-rw-r--r--source/blender/editors/space_action/action_select.c259
-rw-r--r--source/blender/editors/space_file/file_intern.h1
-rw-r--r--source/blender/editors/space_file/file_ops.c105
-rw-r--r--source/blender/editors/space_file/file_utils.c17
-rw-r--r--source/blender/editors/space_file/filelist.c9
-rw-r--r--source/blender/editors/space_file/filesel.c4
-rw-r--r--source/blender/editors/space_graph/graph_ops.c7
-rw-r--r--source/blender/editors/space_graph/graph_select.c83
-rw-r--r--source/blender/editors/space_graph/space_graph.c45
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c11
-rw-r--r--source/blender/editors/space_text/text_ops.c3
-rw-r--r--source/blender/editors/space_view3d/drawobject.c18
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c4
-rw-r--r--source/blender/editors/transform/transform.c15
-rw-r--r--source/blender/editors/transform/transform.h4
-rw-r--r--source/blender/editors/transform/transform_ops.c3
-rw-r--r--source/blender/editors/transform/transform_snap_object.c2
40 files changed, 824 insertions, 214 deletions
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index a82cca9e52a..c24ca1e7027 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -158,7 +158,7 @@ static int add_driver_with_target(
ReportList *UNUSED(reports),
ID *dst_id, const char dst_path[], int dst_index,
ID *src_id, const char src_path[], int src_index,
- PointerRNA *UNUSED(dst_ptr), PropertyRNA *dst_prop,
+ PointerRNA *dst_ptr, PropertyRNA *dst_prop,
PointerRNA *src_ptr, PropertyRNA *src_prop,
short flag, int driver_type)
{
@@ -207,11 +207,15 @@ static int add_driver_with_target(
/* Create a driver variable for the target
* - For transform properties, we want to automatically use "transform channel" instead
* (The only issue is with quat rotations vs euler channels...)
+ * - To avoid problems with transform properties depending on the final transform that they
+ * control (thus creating pseudo-cycles - see T48734), we don't use transform channels
+ * when both the source and destinaions are in same places.
*/
dvar = driver_add_new_variable(driver);
if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) &&
- (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")))
+ (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) &&
+ (src_ptr->data != dst_ptr->data))
{
/* Transform Channel */
DriverTarget *dtar;
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 08a7355694b..7b35a154fc8 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -539,10 +539,10 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
}
/**
- * only called from #ok_bezier_region_lasso
+ * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
*/
-static bool bezier_region_lasso_test(
- const struct KeyframeEdit_LassoData *data_lasso,
+bool keyframe_region_lasso_test(
+ const KeyframeEdit_LassoData *data_lasso,
const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
@@ -564,7 +564,7 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
if (ked->data) {
short ok = 0;
-#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index])
+#define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
@@ -575,11 +575,38 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* check for lasso customdata (KeyframeEdit_LassoData) */
+ if (ked->data) {
+ KeyframeEdit_LassoData *data = ked->data;
+ float pt[2];
+
+ /* late-binding remap of the x values (for summary channels) */
+ /* XXX: Ideally we reset, but it should be fine just leaving it as-is
+ * as the next channel will reset it properly, while the next summary-channel
+ * curve will also reset by itself...
+ */
+ if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
+ data->rectf_scaled->xmin = ked->f1;
+ data->rectf_scaled->xmax = ked->f2;
+ }
+
+ /* only use the x-coordinate of the point; the y is the channel range... */
+ pt[0] = bezt->vec[1][0];
+ pt[1] = ked->channel_y;
+
+ if (keyframe_region_lasso_test(data, pt))
+ return KEYFRAME_OK_KEY;
+ }
+ return 0;
+}
+
/**
- * only called from #ok_bezier_region_circle
+ * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
*/
-static bool bezier_region_circle_test(
- const struct KeyframeEdit_CircleData *data_circle,
+bool keyframe_region_circle_test(
+ const KeyframeEdit_CircleData *data_circle,
const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
@@ -602,7 +629,7 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
if (ked->data) {
short ok = 0;
-#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index])
+#define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
@@ -613,6 +640,33 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* check for circle select customdata (KeyframeEdit_CircleData) */
+ if (ked->data) {
+ KeyframeEdit_CircleData *data = ked->data;
+ float pt[2];
+
+ /* late-binding remap of the x values (for summary channels) */
+ /* XXX: Ideally we reset, but it should be fine just leaving it as-is
+ * as the next channel will reset it properly, while the next summary-channel
+ * curve will also reset by itself...
+ */
+ if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
+ data->rectf_scaled->xmin = ked->f1;
+ data->rectf_scaled->xmax = ked->f2;
+ }
+
+ /* only use the x-coordinate of the point; the y is the channel range... */
+ pt[0] = bezt->vec[1][0];
+ pt[1] = ked->channel_y;
+
+ if (keyframe_region_circle_test(data, pt))
+ return KEYFRAME_OK_KEY;
+ }
+ return 0;
+}
+
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
{
@@ -634,6 +688,10 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
return ok_bezier_region_lasso;
case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_CircleData defined data */
return ok_bezier_region_circle;
+ case BEZT_OK_CHANNEL_LASSO: /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */
+ return ok_bezier_channel_lasso;
+ case BEZT_OK_CHANNEL_CIRCLE: /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
+ return ok_bezier_channel_circle;
default: /* nothing was ok */
return NULL;
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 66b3a63c669..0c0f54f0179 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -1069,6 +1069,9 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
fcu->color_mode = FCURVE_COLOR_AUTO_RGB;
}
+ else if (RNA_property_subtype(prop), PROP_QUATERNION) {
+ fcu->color_mode = FCURVE_COLOR_AUTO_YRGB;
+ }
}
/* insert keyframe */
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index a49b3362155..738496a67c6 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -205,6 +205,36 @@ void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short
}
}
+/* select the frames in this layer that occur within the lasso/circle region specified */
+void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode)
+{
+ bGPDframe *gpf;
+
+ if (gpl == NULL)
+ return;
+
+ /* only select frames which are within the region */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* construct a dummy point coordinate to do this testing with */
+ float pt[2] = {0};
+
+ pt[0] = gpf->framenum;
+ pt[1] = ked->channel_y;
+
+ /* check the necessary regions */
+ if (tool == BEZT_OK_CHANNEL_LASSO) {
+ /* Lasso */
+ if (keyframe_region_lasso_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
+ /* Circle */
+ if (keyframe_region_circle_test(ked->data, pt))
+ gpframe_select(gpf, select_mode);
+ }
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index bd1697b9a54..ac49a51c716 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -652,7 +652,7 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
/* identifiers */
ot->name = "Delete Active Frame";
ot->idname = "GPENCIL_OT_active_frame_delete";
- ot->description = "Delete the active frame for the active Grease Pencil datablock";
+ ot->description = "Delete the active frame for the active Grease Pencil Layer";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -661,6 +661,64 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
ot->poll = gp_actframe_delete_poll;
}
+/* **************** Delete All Active Frames ****************** */
+
+static int gp_actframe_delete_all_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ /* 1) There must be grease pencil data
+ * 2) Hopefully some of the layers have stuff we can use
+ */
+ return (gpd && gpd->layers.first);
+}
+
+static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ bool success = false;
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ /* try to get the "active" frame - but only if it actually occurs on this frame */
+ bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+
+ if (gpf == NULL)
+ continue;
+
+ /* delete it... */
+ gpencil_layer_delframe(gpl, gpf);
+
+ /* we successfully modified something */
+ success = true;
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ if (success) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete");
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete All Active Frames";
+ ot->idname = "GPENCIL_OT_active_frames_delete_all";
+ ot->description = "Delete the active frame(s) of all editable Grease Pencil layers";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_actframe_delete_all_exec;
+ ot->poll = gp_actframe_delete_all_poll;
+}
+
/* ******************* Delete Operator ************************ */
typedef enum eGP_DeleteMode {
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index dd28f6ac531..53fb33eeb9b 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -218,6 +218,7 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot);
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
+void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 405b673c42b..65ee1122b56 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -105,7 +105,7 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
/* Delete Active Frame - For easier video tutorials/review sessions */
/* NOTE: This works even when not in EditMode */
- WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, 0, DKEY);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY);
}
/* ==================== */
@@ -238,7 +238,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, KM_SHIFT, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0);
/* copy + paste */
WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
@@ -364,6 +364,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_isolate);
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
+ WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
WM_operatortype_append(GPENCIL_OT_convert);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index fba2f30e715..a570d586f50 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -97,7 +97,8 @@ typedef enum eGP_StrokeAdd_Result {
typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
GP_PAINTFLAG_STROKEADDED = (1 << 1),
- GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2)
+ GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
+ GP_PAINTFLAG_SELECTMASK = (1 << 3),
} eGPencil_PaintFlags;
@@ -813,18 +814,21 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
BLI_freelinkN(&gpf->strokes, gps);
}
else if (gps->totpoints == 1) {
- gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
-
- /* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
- /* only check if point is inside */
- if (len_v2v2_int(mval, pc1) <= radius) {
- /* free stroke */
- // XXX: pressure sensitive eraser should apply here too?
- MEM_freeN(gps->points);
- if (gps->triangles)
- MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ /* only process if it hasn't been masked out... */
+ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
+ gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval, pc1) <= radius) {
+ /* free stroke */
+ // XXX: pressure sensitive eraser should apply here too?
+ MEM_freeN(gps->points);
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ }
}
}
}
@@ -862,6 +866,11 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
+
+ /* get coordinates of point in screenspace */
gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
@@ -1199,6 +1208,7 @@ static void gp_session_cleanup(tGPsdata *p)
static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
{
Scene *scene = p->scene;
+ ToolSettings *ts = scene->toolsettings;
/* get active layer (or add a new one if non-existent) */
p->gpl = gpencil_layer_getactive(p->gpd);
@@ -1242,6 +1252,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* Ensure this gets set... */
p->gpf = p->gpl->actframe;
+ /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
+ * (though this is only available in editmode)
+ */
+ if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) {
+ p->flags |= GP_PAINTFLAG_SELECTMASK;
+ }
+ }
+
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
//if (G.debug & G_DEBUG)
@@ -1251,7 +1270,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
}
else {
/* Drawing Modes - Add a new frame if needed on the active layer */
- ToolSettings *ts = p->scene->toolsettings;
short add_frame_mode;
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 80f930a0c30..92acfa6c1d2 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -109,7 +109,7 @@ int ED_file_extension_icon(const char *path);
void ED_file_read_bookmarks(void);
-void ED_file_change_dir(struct bContext *C, const bool checkdir);
+void ED_file_change_dir(struct bContext *C);
/* File menu stuff */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 255827db373..de5ab80a88f 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -42,6 +42,7 @@ struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
struct bAnimContext;
+struct KeyframeEditData;
struct PointerRNA;
struct wmWindowManager;
struct wmKeyConfig;
@@ -120,6 +121,7 @@ void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool only
bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl);
void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode);
void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode);
+void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, struct bGPDlayer *gpl, short tool, short select_mode);
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index fae3e3677a0..c0eb88cd982 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -45,14 +45,21 @@ struct Scene;
/* bezt validation */
typedef enum eEditKeyframes_Validate {
+ /* Frame range */
BEZT_OK_FRAME = 1,
BEZT_OK_FRAMERANGE,
+ /* Selection status */
BEZT_OK_SELECTED,
+ /* Values (y-val) only */
BEZT_OK_VALUE,
BEZT_OK_VALUERANGE,
+ /* For graph editor keyframes (2D tests) */
BEZT_OK_REGION,
BEZT_OK_REGION_LASSO,
BEZT_OK_REGION_CIRCLE,
+ /* Only for keyframes a certain Dopesheet channel */
+ BEZT_OK_CHANNEL_LASSO,
+ BEZT_OK_CHANNEL_CIRCLE,
} eEditKeyframes_Validate;
/* ------------ */
@@ -97,20 +104,20 @@ typedef enum eEditKeyframes_Mirror {
} eEditKeyframes_Mirror;
/* use with BEZT_OK_REGION_LASSO */
-struct KeyframeEdit_LassoData {
- const rctf *rectf_scaled;
+typedef struct KeyframeEdit_LassoData {
+ rctf *rectf_scaled;
const rctf *rectf_view;
const int (*mcords)[2];
int mcords_tot;
-};
+} KeyframeEdit_LassoData;
/* use with BEZT_OK_REGION_CIRCLE */
-struct KeyframeEdit_CircleData {
- const rctf *rectf_scaled;
+typedef struct KeyframeEdit_CircleData {
+ rctf *rectf_scaled;
const rctf *rectf_view;
float mval[2];
float radius_squared;
-};
+} KeyframeEdit_CircleData;
/* ************************************************ */
@@ -157,7 +164,8 @@ typedef struct KeyframeEditData {
/* current iteration data */
struct FCurve *fcu; /* F-Curve that is being iterated over */
int curIndex; /* index of current keyframe being iterated over */
-
+ float channel_y; /* y-position of midpoint of the channel (for the dopesheet) */
+
/* flags */
eKeyframeVertOk curflags; /* current flags for the keyframe we're reached in the iteration process */
eKeyframeIterFlags iterflags; /* settings for iteration process */
@@ -258,6 +266,18 @@ short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt);
*/
void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt);
+/* ------ 1.5-D Region Testing Uitls (Lasso/Circle Select) ------- */
+/* XXX: These are temporary, until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */
+
+bool keyframe_region_lasso_test(
+ const KeyframeEdit_LassoData *data_lasso,
+ const float xy[2]);
+
+bool keyframe_region_circle_test(
+ const KeyframeEdit_CircleData *data_circle,
+ const float xy[2]);
+
+
/* ************************************************ */
/* Destructive Editing API (keyframes_general.c) */
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 1f13b46ff2a..2ab788d5e2a 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -35,6 +35,7 @@ struct bContext;
struct wmKeyConfig;
struct MaskLayer;
struct MaskLayerShape;
+struct KeyframeEditData;
/* mask_edit.c */
void ED_mask_get_size(struct ScrArea *sa, int *width, int *height);
@@ -80,6 +81,7 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, boo
bool ED_masklayer_frame_select_check(struct MaskLayer *masklay);
void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode);
void ED_masklayer_frames_select_border(struct MaskLayer *masklay, float min, float max, short select_mode);
+void ED_masklayer_frames_select_region(struct KeyframeEditData *ked, struct MaskLayer *masklay, short tool, short select_mode);
void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode);
void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 9aad340d2fb..a623f5cfb9c 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1020,12 +1020,18 @@ bool UI_context_copy_to_selected_list(
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
-void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index);
+void UI_context_active_but_prop_get(
+ const struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
void UI_context_active_but_prop_handle(struct bContext *C);
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
void UI_context_update_anim_flag(const struct bContext *C);
-void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
-void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
+void UI_context_active_but_prop_get_filebrowser(
+ const struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
+void UI_context_active_but_prop_get_templateID(
+ struct bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop);
/* Styled text draw */
void UI_fontstyle_set(const struct uiFontStyle *fs);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index fac1267cc62..77990066027 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -4323,7 +4323,7 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
/**
- * \param sfunc, bfunc: both get it as \a arg.
+ * \param search_func, bfunc: both get it as \a arg.
* \param arg: user value,
* \param active: when set, button opens with this item visible and selected.
*/
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 133487e1846..f941993a9e1 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -8013,20 +8013,21 @@ uiBut *UI_context_active_but_get(const struct bContext *C)
}
/* helper function for insert keyframe, reset to default, etc operators */
-void UI_context_active_but_prop_get(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
+void UI_context_active_but_prop_get(
+ const bContext *C,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index)
{
uiBut *activebut = ui_context_rna_button_active(C);
- memset(ptr, 0, sizeof(*ptr));
-
if (activebut && activebut->rnapoin.data) {
- *ptr = activebut->rnapoin;
- *prop = activebut->rnaprop;
- *index = activebut->rnaindex;
+ *r_ptr = activebut->rnapoin;
+ *r_prop = activebut->rnaprop;
+ *r_index = activebut->rnaindex;
}
else {
- *prop = NULL;
- *index = 0;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
+ *r_index = 0;
}
}
@@ -9812,10 +9813,17 @@ static int ui_handle_menus_recursive(
retval = ui_pie_handler(C, event, menu);
}
else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) {
+ bool handled = false;
+
if (listbox) {
- retval = ui_handle_list_event(C, event, menu->region, listbox);
+ int retval_test = ui_handle_list_event(C, event, menu->region, listbox);
+ if (retval_test != WM_UI_HANDLER_CONTINUE) {
+ retval = retval_test;
+ handled = true;
+ }
}
- if (retval == WM_UI_HANDLER_CONTINUE) {
+
+ if (handled == false) {
retval = ui_handle_menu_event(
C, event, menu, level,
is_parent_inside, is_parent_menu, is_floating);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index f1f9c4ef0cb..cf3a50d632a 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -231,15 +231,17 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
/* This is for browsing and editing the ID-blocks used */
/* for new/open operators */
-void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
+void UI_context_active_but_prop_get_templateID(
+ bContext *C,
+ PointerRNA *r_ptr, PropertyRNA **r_prop)
{
TemplateID *template;
ARegion *ar = CTX_wm_region(C);
uiBlock *block;
uiBut *but;
- memset(ptr, 0, sizeof(*ptr));
- *prop = NULL;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
if (!ar)
return;
@@ -250,8 +252,8 @@ void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, Pro
if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) {
if (but->func_argN) {
template = but->func_argN;
- *ptr = template->ptr;
- *prop = template->prop;
+ *r_ptr = template->ptr;
+ *r_prop = template->prop;
return;
}
}
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index bcf9ee5c88d..16147bdc7f8 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -201,6 +201,36 @@ void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max,
}
}
+/* select the frames in this layer that occur within the lasso/circle region specified */
+void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *masklay, short tool, short select_mode)
+{
+ MaskLayerShape *masklay_shape;
+
+ if (masklay == NULL)
+ return;
+
+ /* only select frames which are within the region */
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
+ /* construct a dummy point coordinate to do this testing with */
+ float pt[2] = {0};
+
+ pt[0] = masklay_shape->frame;
+ pt[1] = ked->channel_y;
+
+ /* check the necessary regions */
+ if (tool == BEZT_OK_CHANNEL_LASSO) {
+ /* Lasso */
+ if (keyframe_region_lasso_test(ked->data, pt))
+ masklayshape_select(masklay_shape, select_mode);
+ }
+ else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
+ /* Circle */
+ if (keyframe_region_circle_test(ked->data, pt))
+ masklayshape_select(masklay_shape, select_mode);
+ }
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 01be8f848aa..c4e87614732 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -53,6 +53,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_draw.h"
#include "GPU_buffers.h"
/* own include */
@@ -433,7 +434,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
if (ENDIAN_ORDER == B_ENDIAN) {
IMB_convert_rgba_to_abgr(ibuf);
}
- WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
+ GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
a = size[0] * size[1];
while (a--) {
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index efd1ebbd51b..9c2806f6f5a 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -1560,12 +1560,12 @@ void OBJECT_OT_constraints_copy(wmOperatorType *ot)
/************************ add constraint operators *********************/
/* get the Object and/or PoseChannel to use as target */
-static short get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, short add)
+static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add)
{
Object *obact = ED_object_active_context(C);
bPoseChannel *pchanact = BKE_pose_channel_active(obact);
- short only_curve = 0, only_mesh = 0, only_ob = 0;
- short found = 0;
+ bool only_curve = false, only_mesh = false, only_ob = false;
+ bool found = false;
/* clear tar_ob and tar_pchan fields before use
* - assume for now that both always exist...
@@ -1585,7 +1585,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
case CONSTRAINT_TYPE_ROTLIMIT:
case CONSTRAINT_TYPE_SIZELIMIT:
case CONSTRAINT_TYPE_SAMEVOL:
- return 0;
+ return false;
/* restricted target-type constraints -------------- */
/* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */
@@ -1593,26 +1593,26 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
case CONSTRAINT_TYPE_CLAMPTO:
case CONSTRAINT_TYPE_FOLLOWPATH:
case CONSTRAINT_TYPE_SPLINEIK:
- only_curve = 1;
- only_ob = 1;
- add = 0;
+ only_curve = true;
+ only_ob = true;
+ add = false;
break;
/* mesh only? */
case CONSTRAINT_TYPE_SHRINKWRAP:
- only_mesh = 1;
- only_ob = 1;
- add = 0;
+ only_mesh = true;
+ only_ob = true;
+ add = false;
break;
/* object only - add here is ok? */
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
- only_ob = 1;
+ only_ob = true;
break;
}
/* if the active Object is Armature, and we can search for bones, do so... */
- if ((obact->type == OB_ARMATURE) && (only_ob == 0)) {
+ if ((obact->type == OB_ARMATURE) && (only_ob == false)) {
/* search in list of selected Pose-Channels for target */
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
{
@@ -1620,7 +1620,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
if (pchan != pchanact) {
*tar_ob = obact;
*tar_pchan = pchan;
- found = 1;
+ found = true;
break;
}
@@ -1629,36 +1629,50 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
}
/* if not yet found, try selected Objects... */
- if (found == 0) {
+ if (found == false) {
/* search in selected objects context */
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
/* just use the first object we encounter (that isn't the active object)
* and which fulfills the criteria for the object-target that we've got
*/
- if ((ob != obact) &&
- ((!only_curve) || (ob->type == OB_CURVE)) &&
- ((!only_mesh) || (ob->type == OB_MESH)))
- {
- /* set target */
- *tar_ob = ob;
- found = 1;
-
- /* perform some special operations on the target */
- if (only_curve) {
- /* Curve-Path option must be enabled for follow-path constraints to be able to work */
- Curve *cu = (Curve *)ob->data;
- cu->flag |= CU_PATH;
+ if (ob != obact) {
+ /* for armatures in pose mode, look inside the armature for the active bone
+ * so that we set up cross-armature constraints with less effort
+ */
+ if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) &&
+ (!only_curve && !only_mesh))
+ {
+ /* just use the active bone, and assume that it is visible + usable */
+ *tar_ob = ob;
+ *tar_pchan = BKE_pose_channel_active(ob);
+ found = true;
+
+ break;
+ }
+ else if (((!only_curve) || (ob->type == OB_CURVE)) &&
+ ((!only_mesh) || (ob->type == OB_MESH)))
+ {
+ /* set target */
+ *tar_ob = ob;
+ found = true;
+
+ /* perform some special operations on the target */
+ if (only_curve) {
+ /* Curve-Path option must be enabled for follow-path constraints to be able to work */
+ Curve *cu = (Curve *)ob->data;
+ cu->flag |= CU_PATH;
+ }
+
+ break;
}
-
- break;
}
}
CTX_DATA_END;
}
/* if still not found, add a new empty to act as a target (if allowed) */
- if ((found == 0) && (add)) {
+ if ((found == false) && (add)) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Base *base = BASACT, *newbase = NULL;
@@ -1692,7 +1706,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
/* make our new target the new object */
*tar_ob = obt;
- found = 1;
+ found = true;
}
/* return whether there's any target */
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 31b7b584a3a..7a55418b082 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -436,7 +436,7 @@ typedef enum eObClearParentTypes {
EnumPropertyItem prop_clear_parent_types[] = {
{CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent",
- "Completely clear the parenting relationship, including involved modifiers is any"},
+ "Completely clear the parenting relationship, including involved modifiers if any"},
{CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation",
"As 'Clear Parent', but keep the current visual transformations of the object"},
{CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse",
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index 50e10e7e154..408eb38d386 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -59,6 +59,8 @@ void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, s
void ACTION_OT_select_all_toggle(struct wmOperatorType *ot);
void ACTION_OT_select_border(struct wmOperatorType *ot);
+void ACTION_OT_select_lasso(struct wmOperatorType *ot);
+void ACTION_OT_select_circle(struct wmOperatorType *ot);
void ACTION_OT_select_column(struct wmOperatorType *ot);
void ACTION_OT_select_linked(struct wmOperatorType *ot);
void ACTION_OT_select_more(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index f69f9944f8a..a261202b690 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -59,6 +59,8 @@ void action_operatortypes(void)
WM_operatortype_append(ACTION_OT_clickselect);
WM_operatortype_append(ACTION_OT_select_all_toggle);
WM_operatortype_append(ACTION_OT_select_border);
+ WM_operatortype_append(ACTION_OT_select_lasso);
+ WM_operatortype_append(ACTION_OT_select_circle);
WM_operatortype_append(ACTION_OT_select_column);
WM_operatortype_append(ACTION_OT_select_linked);
WM_operatortype_append(ACTION_OT_select_more);
@@ -178,6 +180,14 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
+ /* region select */
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+ kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", true);
+
+ WM_keymap_add_item(keymap, "ACTION_OT_select_circle", CKEY, KM_PRESS, 0, 0);
+
/* column select */
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS);
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA);
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index f2813b2a8d3..0b6d3cb1f60 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -36,6 +36,7 @@
#include "BLI_blenlib.h"
#include "BLI_dlrbTree.h"
+#include "BLI_lasso.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -375,6 +376,264 @@ void ACTION_OT_select_border(wmOperatorType *ot)
ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
}
+/* ******************** Region Select Operators ***************************** */
+/* "Region Select" operators include the Lasso and Circle Select operators.
+ * These two ended up being lumped together, as it was easier in the
+ * original Graph Editor implmentation of these to do it this way.
+ */
+
+static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ KeyframeEditData ked;
+ KeyframeEditFunc ok_cb, select_cb;
+ View2D *v2d = &ac->ar->v2d;
+ rctf rectf, scaled_rectf;
+ float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF);
+
+ /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
+ UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* get beztriple editing/validation funcs */
+ select_cb = ANIM_editkeyframes_select(selectmode);
+ ok_cb = ANIM_editkeyframes_ok(mode);
+
+ /* init editing data */
+ memset(&ked, 0, sizeof(KeyframeEditData));
+ if (mode == BEZT_OK_CHANNEL_LASSO) {
+ KeyframeEdit_LassoData *data_lasso = data;
+ data_lasso->rectf_scaled = &scaled_rectf;
+ ked.data = data_lasso;
+ }
+ else if (mode == BEZT_OK_CHANNEL_CIRCLE) {
+ KeyframeEdit_CircleData *data_circle = data;
+ data_circle->rectf_scaled = &scaled_rectf;
+ ked.data = data;
+ }
+ else {
+ ked.data = &scaled_rectf;
+ }
+
+ /* loop over data, doing region select */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ /* get new vertical minimum extent of channel */
+ ymin = ymax - ACHANNEL_STEP;
+
+ /* compute midpoint of channel (used for testing if the key is in the region or not) */
+ ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF;
+
+ /* if channel is mapped in NLA, apply correction
+ * - Apply to the bounds being checked, not all the keyframe points,
+ * to avoid having scaling everything
+ * - Save result to the scaled_rect, which is all that these operators
+ * will read from
+ */
+ if (adt) {
+ ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
+ ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
+ ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
+ ked.f1 = rectf.xmin;
+ ked.f2 = rectf.xmax;
+ }
+
+ /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks
+ * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these
+ * with the properly remapped ked.f1/f2 values, when needed
+ */
+ scaled_rectf.xmin = ked.f1;
+ scaled_rectf.xmax = ked.f2;
+ scaled_rectf.ymin = ymin;
+ scaled_rectf.ymax = ymax;
+
+ /* perform vertical suitability check (if applicable) */
+ if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) ||
+ !((ymax < rectf.ymin) || (ymin > rectf.ymax)))
+ {
+ /* loop over data selecting */
+ switch (ale->type) {
+ case ANIMTYPE_GPDATABLOCK:
+ {
+ bGPdata *gpd = ale->data;
+ bGPDlayer *gpl;
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ }
+ break;
+ }
+ case ANIMTYPE_GPLAYER:
+ {
+ ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ break;
+ }
+ case ANIMTYPE_MASKDATABLOCK:
+ {
+ Mask *mask = ale->data;
+ MaskLayer *masklay;
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode);
+ }
+ break;
+ }
+ case ANIMTYPE_MASKLAYER:
+ {
+ ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ break;
+ }
+ default:
+ ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
+ break;
+ }
+ }
+
+ /* set minimum extent to be the maximum of the next channel */
+ ymax = ymin;
+ }
+
+ /* cleanup */
+ ANIM_animdata_freelist(&anim_data);
+}
+
+/* ----------------------------------- */
+
+static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ KeyframeEdit_LassoData data_lasso;
+ rcti rect;
+ rctf rect_fl;
+
+ short selectmode;
+ bool extend;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ data_lasso.rectf_view = &rect_fl;
+ data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
+ if (data_lasso.mcords == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* clear all selection if not extending selection */
+ extend = RNA_boolean_get(op->ptr, "extend");
+ if (!extend)
+ deselect_action_keys(&ac, 1, SELECT_SUBTRACT);
+
+ if (!RNA_boolean_get(op->ptr, "deselect"))
+ selectmode = SELECT_ADD;
+ else
+ selectmode = SELECT_SUBTRACT;
+
+ /* get settings from operator */
+ BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
+ BLI_rctf_rcti_copy(&rect_fl, &rect);
+
+ /* apply borderselect action */
+ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
+
+ MEM_freeN((void *)data_lasso.mcords);
+
+ /* send notifier that keyframe selection has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_select_lasso(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Lasso Select";
+ ot->description = "Select keyframe points using lasso selection";
+ ot->idname = "ACTION_OT_select_lasso";
+
+ /* api callbacks */
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = actkeys_lassoselect_exec;
+ ot->poll = ED_operator_action_active;
+ ot->cancel = WM_gesture_lasso_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
+ RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
+ RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
+}
+
+/* ------------------- */
+
+static int action_circle_select_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
+ const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
+
+ KeyframeEdit_CircleData data = {0};
+ rctf rect_fl;
+
+ float x = RNA_int_get(op->ptr, "x");
+ float y = RNA_int_get(op->ptr, "y");
+ float radius = RNA_int_get(op->ptr, "radius");
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ data.mval[0] = x;
+ data.mval[1] = y;
+ data.radius_squared = radius * radius;
+ data.rectf_view = &rect_fl;
+
+ rect_fl.xmin = x - radius;
+ rect_fl.xmax = x + radius;
+ rect_fl.ymin = y - radius;
+ rect_fl.ymax = y + radius;
+
+ /* apply region select action */
+ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data);
+
+ /* send notifier that keyframe selection has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_select_circle(wmOperatorType *ot)
+{
+ ot->name = "Circle Select";
+ ot->description = "Select keyframe points using circle selection";
+ ot->idname = "ACTION_OT_select_circle";
+
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = action_circle_select_exec;
+ ot->poll = ED_operator_action_active;
+ ot->cancel = WM_gesture_circle_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
+ RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
+}
+
/* ******************** Column Select Operator **************************** */
/* This operator works in one of four ways:
* - 1) select all keyframes in the same frame as a selected one (KKEY)
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 71e38f72a7a..a55b18a2212 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -128,6 +128,7 @@ void file_panels_register(struct ARegionType *art);
/* file_utils.c */
void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
+bool file_is_dir(struct SpaceFile *sfile, const char *path);
#endif /* __FILE_INTERN_H__ */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index d83a7d5ea62..c42ff120102 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -208,7 +208,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
BLI_add_slash(params->dir);
}
- ED_file_change_dir(C, false);
+ ED_file_change_dir(C);
retval = FILE_SELECT_DIR;
}
}
@@ -826,7 +826,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop, entry);
BLI_strncpy(params->dir, entry, sizeof(params->dir));
BLI_cleanup_dir(G.main->name, params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -1379,7 +1379,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
BLI_add_slash(sfile->params->dir);
}
- ED_file_change_dir(C, false);
+ ED_file_change_dir(C);
}
/* opening file - sends events now, so things get handled on windowqueue level */
else if (sfile->op) {
@@ -1447,19 +1447,7 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
if (sfile->params) {
if (BLI_parent_dir(sfile->params->dir)) {
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- /* if not browsing in .blend file, we still want to check whether the path is a directory */
- if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX];
- if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) {
- ED_file_change_dir(C, false);
- }
- else {
- ED_file_change_dir(C, true);
- }
- }
- else {
- ED_file_change_dir(C, true);
- }
+ ED_file_change_dir(C);
if (sfile->params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
sfile->params->recursion_level = 0;
@@ -1529,7 +1517,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused))
folderlist_popdir(sfile->folders_prev, sfile->params->dir);
folderlist_pushdir(sfile->folders_next, sfile->params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1561,7 +1549,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
// update folders_prev so we can check for it in folderlist_clear_next()
folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1809,7 +1797,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "open")) {
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1906,17 +1894,35 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
- if (BLI_is_file(sfile->params->dir)) {
- char path[sizeof(sfile->params->dir)];
- BLI_strncpy(path, sfile->params->dir, sizeof(path));
- BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
+ if (!file_is_dir(sfile, sfile->params->dir)) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *group, *name;
+
+ if (BLI_is_file(sfile->params->dir)) {
+ char path[sizeof(sfile->params->dir)];
+ BLI_strncpy(path, sfile->params->dir, sizeof(path));
+ BLI_split_dirfile(path, sfile->params->dir, sfile->params->file,
+ sizeof(sfile->params->dir), sizeof(sfile->params->file));
+ }
+ else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) {
+ if (group) {
+ BLI_path_append(tdir, sizeof(tdir), group);
+ }
+ BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir));
+ if (name) {
+ BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file));
+ }
+ else {
+ sfile->params->file[0] = '\0';
+ }
+ }
}
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- if (BLI_exists(sfile->params->dir)) {
+ if (file_is_dir(sfile, sfile->params->dir)) {
/* if directory exists, enter it immediately */
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -1931,20 +1937,26 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
#endif
else {
const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
+ char tdir[FILE_MAX_LIBEXTRA];
- /* if not, ask to create it and enter if confirmed */
- wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
- PointerRNA ptr;
- WM_operator_properties_create_ptr(&ptr, ot);
- RNA_string_set(&ptr, "directory", sfile->params->dir);
- RNA_boolean_set(&ptr, "open", true);
-
- if (lastdir)
+ /* If we are 'inside' a blend library, we cannot do anything... */
+ if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) {
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
-
-
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
- WM_operator_properties_free(&ptr);
+ }
+ else {
+ /* if not, ask to create it and enter if confirmed */
+ wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_string_set(&ptr, "directory", sfile->params->dir);
+ RNA_boolean_set(&ptr, "open", true);
+
+ if (lastdir)
+ BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+ }
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1971,8 +1983,6 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
BLI_filename_make_safe(sfile->params->file);
if (matches) {
- /* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */
- sfile->params->file[0] = '\0';
/* replace the pattern (or filename that the user typed in, with the first selected file of the match */
BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file));
@@ -1980,30 +1990,17 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
}
if (matches == 1) {
-
BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file);
/* if directory, open it and empty filename field */
- if (BLI_is_dir(filepath)) {
+ if (file_is_dir(sfile, filepath)) {
BLI_cleanup_dir(G.main->name, filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
- ED_file_change_dir(C, true);
+ ED_file_change_dir(C);
UI_textbutton_activate_but(C, but);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
- else if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX];
- BLI_add_slash(filepath);
- if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) {
- BLI_cleanup_dir(G.main->name, filepath);
- BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
- sfile->params->file[0] = '\0';
- ED_file_change_dir(C, false);
- UI_textbutton_activate_but(C, but);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
- }
- }
}
else if (matches > 1) {
file_draw_check(C);
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index 3c007f25da3..f19e301064d 100644
--- a/source/blender/editors/space_file/file_utils.c
+++ b/source/blender/editors/space_file/file_utils.c
@@ -25,6 +25,9 @@
*/
#include "BLI_rect.h"
+#include "BLI_fileops.h"
+
+#include "BLO_readfile.h"
#include "BKE_context.h"
@@ -45,3 +48,17 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r
BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x,
ymax - layout->tile_h - layout->tile_border_y, ymax);
}
+
+/* Cannot directly use BLI_is_dir in libloading context... */
+bool file_is_dir(struct SpaceFile *sfile, const char *path)
+{
+ if (sfile->params->type == FILE_LOADLIB) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *name;
+ if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) {
+ /* .blend file itself and group are considered as directories, not final datablock names. */
+ return name ? false : true;
+ }
+ }
+ return BLI_is_dir(path);
+}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index fc3341bfb92..5e9eb1f9207 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -624,7 +624,7 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root)
static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
{
bool is_filtered;
- char path[FILE_MAX_LIBEXTRA], dir[FILE_MAXDIR], *group, *name;
+ char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
BLI_join_dirfile(path, sizeof(path), root, file->relpath);
@@ -697,7 +697,7 @@ void filelist_filter(FileList *filelist)
if (filelist->max_recursion) {
/* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
* root path is a blend file. */
- char dir[FILE_MAXDIR];
+ char dir[FILE_MAX_LIBEXTRA];
if (!filelist_islibrary(filelist, dir, NULL)) {
filelist->filter_data.flags |= FLF_HIDE_LIB_DIR;
}
@@ -947,7 +947,7 @@ static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir
static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir)
{
- char dir[FILE_MAXDIR];
+ char dir[FILE_MAX_LIBEXTRA];
if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) {
/* if not a valid library, we need it to be a valid directory! */
BLI_make_exist(r_dir);
@@ -2113,6 +2113,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist, const int index
return 0;
}
+/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
{
return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL);
@@ -2208,7 +2209,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
FileListInternEntry *entry;
LinkNode *ln, *names;
int i, nnames, idcode = 0, nbr_entries = 0;
- char dir[FILE_MAX], *group;
+ char dir[FILE_MAX_LIBEXTRA], *group;
bool ok;
struct BlendHandle *libfiledata = NULL;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 2a3f964f477..2d28108f544 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -576,7 +576,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar)
return sfile->layout;
}
-void ED_file_change_dir(bContext *C, const bool checkdir)
+void ED_file_change_dir(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -590,7 +590,7 @@ void ED_file_change_dir(bContext *C, const bool checkdir)
sfile->params->filter_search[0] = '\0';
sfile->params->active_file = -1;
- if (checkdir && !BLI_is_dir(sfile->params->dir)) {
+ if (!file_is_dir(sfile, sfile->params->dir)) {
BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir));
/* could return but just refresh the current dir */
}
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 6b860990c10..478dbd3d9c0 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -555,19 +555,20 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
RNA_boolean_set(kmi->ptr, "include_handles", false);
-
+
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "axis_range", false);
RNA_boolean_set(kmi->ptr, "include_handles", true);
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "axis_range", true);
RNA_boolean_set(kmi->ptr, "include_handles", true);
-
+
+ /* region select */
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "deselect", false);
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "deselect", true);
-
+
WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0);
/* column select */
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index eb786d872ec..67b960bfa53 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -210,6 +210,8 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot)
* -> ALT-BKEY - depending on which axis of the region was larger...
* -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE)
* -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE)
+ *
+ * The selection backend is also reused for the Lasso and Circle select operators.
*/
/* Borderselect only selects keyframes now, as overshooting handles often get caught too,
@@ -245,12 +247,12 @@ static void borderselect_graphkeys(
/* init editing data */
memset(&ked, 0, sizeof(KeyframeEditData));
if (mode == BEZT_OK_REGION_LASSO) {
- struct KeyframeEdit_LassoData *data_lasso = data;
+ KeyframeEdit_LassoData *data_lasso = data;
data_lasso->rectf_scaled = &scaled_rectf;
ked.data = data_lasso;
}
else if (mode == BEZT_OK_REGION_CIRCLE) {
- struct KeyframeEdit_CircleData *data_circle = data;
+ KeyframeEdit_CircleData *data_circle = data;
data_circle->rectf_scaled = &scaled_rectf;
ked.data = data;
}
@@ -265,27 +267,27 @@ static void borderselect_graphkeys(
}
else
mapping_flag = ANIM_UNITCONV_ONLYKEYS;
-
+
mapping_flag |= ANIM_get_normalization_flags(ac);
-
+
/* loop over data, doing border select */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float offset;
float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
-
+
/* apply NLA mapping to all the keyframes, since it's easier than trying to
* guess when a callback might use something different
*/
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, incl_handles == 0);
-
+
scaled_rectf.xmin = rectf.xmin;
scaled_rectf.xmax = rectf.xmax;
scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
-
+
/* set horizontal range (if applicable)
* NOTE: these values are only used for x-range and y-range but not region
* (which uses ked.data, i.e. rectf)
@@ -406,37 +408,41 @@ void GRAPH_OT_select_border(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria");
}
+
+/* ------------------- */
+
static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+
+ KeyframeEdit_LassoData data_lasso = {0};
rcti rect;
rctf rect_fl;
+
short selectmode;
bool incl_handles;
bool extend;
-
- struct KeyframeEdit_LassoData data_lasso;
-
+
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
-
+
data_lasso.rectf_view = &rect_fl;
data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
if (data_lasso.mcords == NULL)
return OPERATOR_CANCELLED;
-
+
/* clear all selection if not extending selection */
extend = RNA_boolean_get(op->ptr, "extend");
if (!extend)
deselect_graph_keys(&ac, 1, SELECT_SUBTRACT, true);
-
+
if (!RNA_boolean_get(op->ptr, "deselect"))
selectmode = SELECT_ADD;
else
selectmode = SELECT_SUBTRACT;
-
- if (ac.spacetype == SPACE_IPO) {
+
+ {
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
if (selectmode == SELECT_ADD) {
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
@@ -446,60 +452,57 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
}
}
- else {
- incl_handles = false;
- }
-
-
+
/* get settings from operator */
BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
-
BLI_rctf_rcti_copy(&rect_fl, &rect);
-
+
/* apply borderselect action */
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
-
+
MEM_freeN((void *)data_lasso.mcords);
-
-
+
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+
return OPERATOR_FINISHED;
}
-
void GRAPH_OT_select_lasso(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Lasso Select";
ot->description = "Select keyframe points using lasso selection";
ot->idname = "GRAPH_OT_select_lasso";
-
+
/* api callbacks */
ot->invoke = WM_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
ot->exec = graphkeys_lassoselect_exec;
ot->poll = graphop_visible_keyframes_poll;
ot->cancel = WM_gesture_lasso_cancel;
-
+
/* flags */
ot->flag = OPTYPE_UNDO;
-
+
/* properties */
RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
}
+/* ------------------- */
+
static int graph_circle_select_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
- short selectmode;
- bool incl_handles;
+ const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
+ bool incl_handles = false;
+
+ KeyframeEdit_CircleData data = {0};
rctf rect_fl;
- struct KeyframeEdit_CircleData data;
+
float x = RNA_int_get(op->ptr, "x");
float y = RNA_int_get(op->ptr, "y");
float radius = RNA_int_get(op->ptr, "radius");
@@ -507,23 +510,18 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
-
+
data.mval[0] = x;
data.mval[1] = y;
data.radius_squared = radius * radius;
data.rectf_view = &rect_fl;
- if (gesture_mode == GESTURE_MODAL_SELECT)
- selectmode = SELECT_ADD;
- else
- selectmode = SELECT_SUBTRACT;
-
rect_fl.xmin = x - radius;
rect_fl.xmax = x + radius;
rect_fl.ymin = y - radius;
rect_fl.ymax = y + radius;
- if (ac.spacetype == SPACE_IPO) {
+ {
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
if (selectmode == SELECT_ADD) {
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
@@ -533,10 +531,7 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
}
}
- else {
- incl_handles = false;
- }
-
+
/* apply borderselect action */
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index a7284694f64..8ae5932f3fd 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -611,6 +611,51 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
}
break;
}
+ case FCURVE_COLOR_AUTO_YRGB:
+ {
+ /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */
+ float *col = fcu->color;
+
+ switch (fcu->array_index) {
+ case 1:
+ UI_GetThemeColor3fv(TH_AXIS_X, col);
+ break;
+ case 2:
+ UI_GetThemeColor3fv(TH_AXIS_Y, col);
+ break;
+ case 3:
+ UI_GetThemeColor3fv(TH_AXIS_Z, col);
+ break;
+
+ case 0:
+ {
+ /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */
+ float c1[3], c2[3];
+ float h1[3], h2[3];
+ float hresult[3];
+
+ /* - get colors (rgb) */
+ UI_GetThemeColor3fv(TH_AXIS_X, c1);
+ UI_GetThemeColor3fv(TH_AXIS_Y, c2);
+
+ /* - perform blending in HSV space (to keep brightness similar) */
+ rgb_to_hsv_v(c1, h1);
+ rgb_to_hsv_v(c2, h2);
+
+ interp_v3_v3v3(hresult, h1, h2, 0.5f);
+
+ /* - convert back to RGB for display */
+ hsv_to_rgb_v(hresult, col);
+ break;
+ }
+
+ default:
+ /* 'unknown' color - bluish so as to not conflict with handles */
+ col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
+ break;
+ }
+ break;
+ }
case FCURVE_COLOR_AUTO_RAINBOW:
default:
{
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 687869ae727..57d9ff7825b 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -399,13 +399,22 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id"));
/* check for invalid states */
- if (soops == NULL)
+ if (soops == NULL) {
return OPERATOR_CANCELLED;
+ }
if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
+ BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')",
+ old_id->name, new_id->name);
return OPERATOR_CANCELLED;
}
+ if (old_id->lib) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Old ID '%s' is linked from a library, indirect usages of this datablock will not be remapped",
+ old_id->name);
+ }
+
BKE_libblock_remap(bmain, old_id, new_id,
ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index d404e7aaf15..94ed280f792 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -384,8 +384,7 @@ static int text_unlink_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- BKE_text_unlink(bmain, text);
- BKE_libblock_free(bmain, text);
+ BKE_libblock_delete(bmain, text);
text_drawcache_tag_update(st, 1);
WM_event_add_notifier(C, NC_TEXT | NA_REMOVED, NULL);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index c32de6eafc3..3b1ce5f8ab0 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -7032,7 +7032,7 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa
MVert *mv = &data->mvert[index];
if (!(mv->flag & ME_HIDE)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
glVertex3fv(co);
}
}
@@ -7057,7 +7057,7 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3]
BMVert *eve = BM_vert_at_index(data->bm, index);
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
glVertex3fv(co);
}
}
@@ -7076,7 +7076,7 @@ static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index)
BMEdge *eed = BM_edge_at_index(data->bm, index);
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(data->offset + index);
+ GPU_select_index_set(data->offset + index);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -7090,7 +7090,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
}
/**
- * dont set #WM_framebuffer_index_set. just use to mask other
+ * dont set #GPU_framebuffer_index_set. just use to mask other
*/
static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index)
{
@@ -7109,7 +7109,7 @@ static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int inde
BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -7122,7 +7122,7 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce
BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
glVertex3fv(cent);
}
@@ -7153,7 +7153,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index)
{
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
@@ -7162,7 +7162,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
Mesh *me = userData;
if (!(me->mpoly[index].flag & ME_HIDE)) {
- WM_framebuffer_index_set(index + 1);
+ GPU_select_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -7170,7 +7170,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
}
}
-/* must have called WM_framebuffer_index_set beforehand */
+/* must have called GPU_framebuffer_index_set beforehand */
static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index)
{
Mesh *me = userData;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 64b12498ae2..dcab05c80d6 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1483,7 +1483,7 @@ unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
BLI_endian_switch_uint32(&col);
}
- return WM_framebuffer_to_index(col);
+ return GPU_select_to_index(col);
}
/* reads full rect, converts indices */
@@ -1516,7 +1516,7 @@ ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int
IMB_convert_rgba_to_abgr(ibuf_clip);
}
- WM_framebuffer_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
+ GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
if ((clip.xmin == xmin) &&
(clip.xmax == xmax) &&
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index fd7179d06dd..148db20b41d 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -93,6 +93,8 @@
#include "UI_interface.h"
+#include "GPU_draw.h"
+
#include "view3d_intern.h" /* own include */
float ED_view3d_select_dist_px(void)
@@ -1687,7 +1689,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo
if (ENDIAN_ORDER == B_ENDIAN) {
IMB_convert_rgba_to_abgr(ibuf);
}
- WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
+ GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
a = size[0] * size[1];
while (a--) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 943490bbc3a..c94b0d53468 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1202,8 +1202,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
if (t->flag & T_PROP_EDIT) {
float fac = 1.0f + 0.005f *(event->y - event->prevy);
t->prop_size *= fac;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
- t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
+ t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->far), T_PROP_SIZE_MIN);
+ }
+ else {
+ t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1212,8 +1216,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_UP:
if (t->flag & T_PROP_EDIT) {
t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
- if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
+ if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+ }
+ else {
+ t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX);
+ }
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1222,6 +1230,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_PROPSIZE_DOWN:
if (t->flag & T_PROP_EDIT) {
t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
+ t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN);
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 4e8aa0cc20b..da448faa16b 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -592,6 +592,10 @@ typedef struct TransInfo {
#define POINT_INIT 4
#define MULTI_POINTS 8
+/* Hard min/max for proportional size. */
+#define T_PROP_SIZE_MIN 1e-6f
+#define T_PROP_SIZE_MAX 1e12f
+
bool initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, const struct wmEvent *event, int mode);
void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op);
int transformEvent(TransInfo *t, const struct wmEvent *event);
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 2fb92d73515..6e399d9fde3 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -528,7 +528,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0,
"Proportional Editing Falloff", "Falloff type for proportional editing mode");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
- RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100);
+ RNA_def_float(ot->srna, "proportional_size", 1, T_PROP_SIZE_MIN, T_PROP_SIZE_MAX,
+ "Proportional Size", "", 0.001f, 100.0f);
}
if (flags & P_SNAP) {
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index d706c574d1f..1db4ee0e2e5 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -1627,7 +1627,7 @@ static bool transform_snap_context_project_view3d_mixed_impl(
* Given a 2D region value, snap to vert/edge/face.
*
* \param sctx: Snap context.
- * \param mval: Screenspace coordinate.
+ * \param mval_fl: Screenspace coordinate.
* \param dist_px: Maximum distance to snap (in pixels).
* \param use_depth: Snap to the closest element, use when using more than one snap type.
* \param r_co: hit location.