Blender V5.0
transform_mode_timeslide.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cstdlib>
11
12#include "MEM_guardedalloc.h"
13
14#include "BLI_math_vector.h"
15#include "BLI_string_utf8.h"
16
17#include "BKE_nla.hh"
18#include "BKE_unit.hh"
19
20#include "ED_screen.hh"
21
22#include "UI_view2d.hh"
23
24#include "BLT_translation.hh"
25
26#include "UI_interface_types.hh"
27
28#include "transform.hh"
29#include "transform_convert.hh"
30
31#include "transform_mode.hh"
32
33namespace blender::ed::transform {
34
35/* -------------------------------------------------------------------- */
38
39static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW_STR])
40{
41 char tvec[NUM_STR_REP_LEN * 3];
42
43 if (hasNumInput(&t->num)) {
44 outputNumInput(&(t->num), tvec, t->scene->unit);
45 }
46 else {
47 const float *range = static_cast<const float *>(t->custom.mode.data);
48 float minx = range[0];
49 float maxx = range[1];
50 float cval = t->values_final[0];
51 float val;
52
53 val = 2.0f * (cval - sval) / (maxx - minx);
54 CLAMP(val, -1.0f, 1.0f);
55
56 BLI_snprintf_utf8(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
57 }
58
59 BLI_snprintf_utf8(str, UI_MAX_DRAW_STR, IFACE_("TimeSlide: %s"), &tvec[0]);
60}
61
62static void applyTimeSlideValue(TransInfo *t, float sval, float cval)
63{
64 int i;
65 const float *range = static_cast<const float *>(t->custom.mode.data);
66 float minx = range[0];
67 float maxx = range[1];
68
69 /* Set value for drawing black line. */
70 if (t->spacetype == SPACE_ACTION) {
71 SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
72 saction->timeslide = cval;
73 }
74
75 /* It doesn't matter whether we apply to t->data or
76 * t->data2d, but t->data2d is more convenient. */
78 TransData *td = tc->data;
79 for (i = 0; i < tc->data_len; i++, td++) {
80 /* It is assumed that td->extra is a pointer to the AnimData,
81 * whose active action is where this keyframe comes from
82 * (this is only valid when not in NLA). */
83 AnimData *adt = static_cast<AnimData *>((t->spacetype != SPACE_NLA) ? td->extra : nullptr);
84
85 /* Only apply to data if in range. */
86 if ((sval > minx) && (sval < maxx)) {
87 float cvalc = std::clamp(cval, minx, maxx);
88 float timefac;
89 float *dst;
90 float ival;
91
92 if (td->val) {
93 dst = td->val;
94 ival = td->ival;
95 }
96 else {
97 dst = &td->loc[0];
98 ival = td->iloc[0];
99 }
100
101 /* NLA mapping magic here works as follows:
102 * - `ival` goes from strip time to global time.
103 * - Calculation is performed into `td->val` in global time
104 * (since `sval` and min/max are all in global time).
105 * - `td->val` then gets put back into strip time.
106 */
107 if (adt) {
108 /* Strip to global. */
110 }
111
112 /* Left half? */
113 if (ival < sval) {
114 timefac = (sval - ival) / (sval - minx);
115 *dst = cvalc - timefac * (cvalc - minx);
116 }
117 else {
118 timefac = (ival - sval) / (maxx - sval);
119 *dst = cvalc + timefac * (maxx - cvalc);
120 }
121
122 if (adt) {
123 /* Global to strip. */
125 }
126 }
127 }
128 }
129}
130
132{
133 View2D *v2d = (View2D *)t->view;
134 float cval[2], sval[2];
135 const float *range = static_cast<const float *>(t->custom.mode.data);
136 float minx = range[0];
137 float maxx = range[1];
138 char str[UI_MAX_DRAW_STR];
139
140 /* Calculate mouse co-ordinates. */
141 UI_view2d_region_to_view(v2d, t->mval[0], t->mval[1], &cval[0], &cval[1]);
142 UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &sval[0], &sval[1]);
143
144 /* `t->values_final[0]` stores `cval[0]`,
145 * which is the current mouse-pointer location (in frames). */
146 /* XXX Need to be able to repeat this. */
147 // t->values_final[0] = cval[0]; /* UNUSED (reset again later). */
148
149 /* Handle numeric-input stuff. */
150 t->vec[0] = 2.0f * (cval[0] - sval[0]) / (maxx - minx);
151 applyNumInput(&t->num, &t->vec[0]);
152 t->values_final[0] = (maxx - minx) * t->vec[0] / 2.0f + sval[0];
153
154 headerTimeSlide(t, sval[0], str);
155 applyTimeSlideValue(t, sval[0], t->values_final[0]);
156
157 recalc_data(t);
158
160}
161
162static void initTimeSlide(TransInfo *t, wmOperator * /*op*/)
163{
164 /* This tool is only really available in the Action Editor. */
165 if (t->spacetype == SPACE_ACTION) {
166 SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
167
168 /* Set flag for drawing stuff. */
169 saction->flag |= SACTION_MOVING;
170 }
171 else {
172 t->state = TRANS_CANCEL;
173 }
174
175 t->mode = TFM_TIME_SLIDE;
176
178
179 {
180 Scene *scene = t->scene;
181 float *range;
182 t->custom.mode.data = range = static_cast<float *>(
183 MEM_mallocN(sizeof(float[2]), "TimeSlide Min/Max"));
184 t->custom.mode.use_free = true;
185
186 float min = 999999999.0f, max = -999999999.0f;
187 int i;
189 TransData *td = tc->data;
190 for (i = 0; i < tc->data_len; i++, td++) {
191 AnimData *adt = static_cast<AnimData *>((t->spacetype != SPACE_NLA) ? td->extra : nullptr);
192 float val = *(td->val);
193
194 /* Strip/action time to global (mapped) time. */
195 if (adt) {
197 }
198
199 min = std::min(min, val);
200 max = std::max(max, val);
201 }
202 }
203
204 if (min == max) {
205 /* Just use the current frame ranges. */
206 min = float(PSFRA);
207 max = float(PEFRA);
208 }
209
210 range[0] = min;
211 range[1] = max;
212 }
213
214 /* Numeric-input has max of (n-1). */
215 t->idx_max = 0;
216 t->num.flag = 0;
217 t->num.idx_max = t->idx_max;
218
219 /* Initialize snap like for everything else. */
220 t->increment[0] = 1.0f;
221 t->increment_precision = 1.0f;
222
223 copy_v3_fl(t->num.val_inc, t->increment[0]);
224 t->num.unit_sys = t->scene->unit.system;
225 /* No time unit supporting frames currently. */
226 t->num.unit_type[0] = B_UNIT_NONE;
227}
228
230
232 /*flags*/ T_NULL_ONE,
233 /*init_fn*/ initTimeSlide,
234 /*transform_fn*/ applyTimeSlide,
235 /*transform_matrix_fn*/ nullptr,
236 /*handle_event_fn*/ nullptr,
237 /*snap_distance_fn*/ nullptr,
238 /*snap_apply_fn*/ nullptr,
239 /*draw_fn*/ nullptr,
240};
241
242} // namespace blender::ed::transform
@ NLATIME_CONVERT_MAP
Definition BKE_nla.hh:552
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:549
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, eNlaTime_ConvertModes mode)
@ B_UNIT_NONE
Definition BKE_unit.hh:136
MINLINE void copy_v3_fl(float r[3], float f)
size_t size_t size_t BLI_snprintf_utf8(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define CLAMP(a, b, c)
#define IFACE_(msgid)
@ SACTION_MOVING
#define PSFRA
#define PEFRA
@ SPACE_ACTION
@ SPACE_NLA
#define NUM_STR_REP_LEN
bool applyNumInput(NumInput *n, float *vec)
Definition numinput.cc:190
void outputNumInput(NumInput *n, char *str, const UnitSettings &unit_settings)
Definition numinput.cc:88
bool hasNumInput(const NumInput *n)
Definition numinput.cc:171
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:851
Read Guarded memory(de)allocation.
#define UI_MAX_DRAW_STR
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1668
nullptr float
#define str(s)
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
void recalc_data(TransInfo *t)
static void applyTimeSlideValue(TransInfo *t, float sval, float cval)
static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW_STR])
static void initTimeSlide(TransInfo *t, wmOperator *)
static void applyTimeSlide(TransInfo *t)
void * first
short idx_max
float val_inc[NUM_MAX_ELEMENTS]
int unit_type[NUM_MAX_ELEMENTS]
short flag
struct UnitSettings unit
ListBase spacedata
TransCustomDataContainer custom
Definition transform.hh:974
i
Definition text_draw.cc:230
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
Definition transform.hh:42
conversion and adaptation of different datablocks to a common struct.
transform modes used by different operators.