Blender V5.0
wm_operator_utils.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <cmath>
12
13#include "BLI_array.hh"
14#include "BLI_string.h"
15
16#include "BKE_context.hh"
17#include "BKE_global.hh"
18#include "BKE_layer.hh"
19
20#include "RNA_access.hh"
21#include "RNA_define.hh"
22
23#include "WM_api.hh" /* Own include. */
24#include "WM_types.hh"
25
26#include "MEM_guardedalloc.h"
27
28#include "ED_object.hh"
29#include "ED_screen.hh"
30
31using blender::Array;
32using blender::Vector;
33
34/* -------------------------------------------------------------------- */
37
39 const wmEvent *event)
40{
41 if (event->val != KM_PRESS) {
42 if (retval & OPERATOR_PASS_THROUGH) {
43 /* Operators that use this function should either finish or cancel,
44 * otherwise non-press events will be passed through to other key-map items. */
45 BLI_assert((retval & ~OPERATOR_PASS_THROUGH) != 0);
46 if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
47 retval &= ~OPERATOR_PASS_THROUGH;
48 }
49 }
50 }
51 return retval;
52}
53
55
56/* -------------------------------------------------------------------- */
64
66 struct {
67 float mval[2];
70 struct {
71 float prop_value;
72 bool is_snap;
75 float range[2];
76
77 struct {
81};
82
84 ValueInteraction *inter,
85 const wmEvent *event,
86 const float value_final,
87 const float range[2])
88{
89
92
93 inter->init.mval[0] = event->mval[0];
94 inter->init.mval[1] = event->mval[1];
95 inter->init.prop_value = value_final;
96 inter->prev.prop_value = value_final;
97 inter->range[0] = range[0];
98 inter->range[1] = range[1];
99}
100
102 bContext *C, ValueInteraction *inter, const wmEvent *event, PointerRNA *ptr, PropertyRNA *prop)
103{
104 float range[2];
105 float step, precision;
106 RNA_property_float_ui_range(ptr, prop, &range[0], &range[1], &step, &precision);
107 const float value_final = RNA_property_float_get(ptr, prop);
108 interactive_value_init(C, inter, event, value_final, range);
109}
110
112{
113 ED_area_status_text(inter->context_vars.area, nullptr);
114}
115
117 const wmEvent *event,
118 float *r_value_final)
119{
120 const int mval_axis = 0;
121
122 const float value_scale = 4.0f; /* Could be option. */
123 const float value_range = inter->range[1] - inter->range[0];
124 const int mval_curr = event->mval[mval_axis];
125 const int mval_init = inter->init.mval[mval_axis];
126 float value_delta = (inter->init.prop_value +
127 ((float(mval_curr - mval_init) / inter->context_vars.region->winx) *
128 value_range)) *
129 value_scale;
130 if (event->modifier & KM_CTRL) {
131 const double snap = 0.1;
132 value_delta = roundf(double(value_delta) / snap) * snap;
133 }
134 if (event->modifier & KM_SHIFT) {
135 value_delta *= 0.1f;
136 }
137 const float value_final = inter->init.prop_value + value_delta;
138
139 const bool changed = value_final != inter->prev.prop_value;
140 if (changed) {
141 /* Set the property for the operator and call its modal function. */
142 char str[64];
143 SNPRINTF(str, "%.4f", value_final);
145 }
146
147 inter->prev.prop_value = value_final;
148 inter->prev.is_snap = (event->modifier & KM_CTRL) != 0;
149 inter->prev.is_precise = (event->modifier & KM_SHIFT) != 0;
150
151 *r_value_final = value_final;
152 return changed;
153}
154
156
157/* -------------------------------------------------------------------- */
162
174
175/* Internal callback to free. */
177{
179 if (cd) {
181 MEM_delete(cd);
182 }
183
184 G.moving &= ~G_TRANSFORM_EDIT;
185}
186
188{
190 for (std::unique_ptr<blender::ed::object::XFormObjectData> &xod : cd->objects_xform) {
193 }
194}
195
197{
199}
200
202{
203 if (RNA_property_is_set(op->ptr, op->type->prop)) {
204 return WM_operator_call_notest(C, op);
205 }
206
207 const Scene *scene = CTX_data_scene(C);
208 ViewLayer *view_layer = CTX_data_view_layer(C);
210 scene, view_layer, CTX_wm_view3d(C));
211 if (objects.is_empty()) {
212 return OPERATOR_CANCELLED;
213 }
214
215 ObCustomData_ForEditMode *cd = MEM_new<ObCustomData_ForEditMode>(__func__);
217 cd->wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input");
218 cd->is_active = !cd->wait_for_input;
219 cd->is_first = true;
220
221 if (cd->wait_for_input == false) {
222 interactive_value_init_from_property(C, &cd->inter, event, op->ptr, op->type->prop);
223 }
224
225 cd->objects_xform.reinitialize(objects.size());
226 for (const int i : objects.index_range()) {
227 Object *obedit = objects[i];
229 static_cast<ID *>(obedit->data));
230 }
231
232 op->customdata = cd;
233
235 G.moving |= G_TRANSFORM_EDIT;
236
238}
239
241{
243
244 /* Special case, check if we release the event that activated this operator. */
245 if ((event->type == cd->launch_event) && (event->val == KM_RELEASE)) {
246 if (cd->wait_for_input == false) {
248 return OPERATOR_FINISHED;
249 }
250 }
251
252 switch (event->type) {
253 case MOUSEMOVE:
254 case EVT_LEFTCTRLKEY:
255 case EVT_RIGHTCTRLKEY:
256 case EVT_LEFTSHIFTKEY:
257 case EVT_RIGHTSHIFTKEY: {
258 float value_final;
259 if (cd->is_active && interactive_value_update(&cd->inter, event, &value_final)) {
261
262 RNA_property_float_set(op->ptr, op->type->prop, value_final);
263 if (cd->is_first == false) {
265 }
266
267 wm->op_undo_depth++;
268 const wmOperatorStatus retval = op->type->exec(C, op);
269 OPERATOR_RETVAL_CHECK(retval);
270 wm->op_undo_depth--;
271
272 cd->is_first = false;
273
274 if ((retval & OPERATOR_FINISHED) == 0) {
276 return OPERATOR_CANCELLED;
277 }
278 }
279 break;
280 }
281 case EVT_RETKEY:
282 case EVT_PADENTER:
283 case LEFTMOUSE: {
284 if (cd->wait_for_input) {
285 if (event->val == KM_PRESS) {
286 if (cd->is_active == false) {
287 cd->is_active = true;
288 interactive_value_init_from_property(C, &cd->inter, event, op->ptr, op->type->prop);
289 }
290 }
291 else if (event->val == KM_RELEASE) {
292 if (cd->is_active == true) {
294 return OPERATOR_FINISHED;
295 }
296 }
297 }
298 else {
299 if (event->val == KM_RELEASE) {
301 return OPERATOR_FINISHED;
302 }
303 }
304 break;
305 }
306 case EVT_ESCKEY:
307 case RIGHTMOUSE: {
308 if (event->val == KM_PRESS) {
309 if (cd->is_active == true) {
311 }
313 return OPERATOR_CANCELLED;
314 }
315 break;
316 }
317 default: {
318 break;
319 }
320 }
322}
323
325{
326 PropertyRNA *prop;
327
328 BLI_assert(ot->modal == nullptr);
329 BLI_assert(ot->invoke == nullptr);
330 BLI_assert(ot->cancel == nullptr);
331 BLI_assert(ot->prop != nullptr);
332
333 ot->invoke = op_generic_value_invoke;
334 ot->modal = op_generic_value_modal;
335 ot->cancel = op_generic_value_cancel;
336
337 prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
339}
340
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
@ G_TRANSFORM_EDIT
blender::Vector< Object * > BKE_view_layer_array_from_objects_in_edit_mode_unique_data(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:604
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
#define OPERATOR_RETVAL_CHECK(ret)
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:851
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
@ KM_CTRL
Definition WM_types.hh:279
@ KM_SHIFT
Definition WM_types.hh:278
@ KM_PRESS
Definition WM_types.hh:311
@ KM_RELEASE
Definition WM_types.hh:312
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
int64_t size() const
bool is_empty() const
IndexRange index_range() const
nullptr float
#define roundf(x)
#define str(s)
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
#define G(x, y, z)
void data_xform_restore(XFormObjectData &xod)
std::unique_ptr< XFormObjectData > data_xform_create_from_edit_mode(ID *id)
void data_xform_tag_update(XFormObjectData &xod)
vector snap(vector a, vector b)
Definition node_math.h:97
static void init(bNodeTree *, bNode *node)
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_ui_range(PointerRNA *ptr, PropertyRNA *prop, float *softmin, float *softmax, float *step, float *precision)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition DNA_ID.h:414
blender::Array< std::unique_ptr< blender::ed::object::XFormObjectData > > objects_xform
struct ValueInteraction::@030221123137037035342035211340273355113043106176 prev
struct ValueInteraction::@235130235375370360206126274303031112330313051365 init
struct ValueInteraction::@376321142340254065172250025356053176150247346202 context_vars
wmEventModifierFlag modifier
Definition WM_types.hh:774
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
wmOperatorStatus(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1049
PropertyRNA * prop
Definition WM_types.hh:1139
struct wmOperatorType * type
struct PointerRNA * ptr
i
Definition text_draw.cc:230
int WM_userdef_event_type_from_keymap_type(int kmitype)
wmOperatorStatus WM_operator_call_notest(bContext *C, wmOperator *op)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ RIGHTMOUSE
@ EVT_RIGHTCTRLKEY
@ EVT_LEFTCTRLKEY
@ EVT_PADENTER
@ MOUSEMOVE
@ LEFTMOUSE
@ EVT_ESCKEY
@ EVT_RIGHTSHIFTKEY
@ EVT_LEFTSHIFTKEY
@ EVT_RETKEY
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
static void op_generic_value_restore(wmOperator *op)
static wmOperatorStatus op_generic_value_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void interactive_value_init_from_property(bContext *C, ValueInteraction *inter, const wmEvent *event, PointerRNA *ptr, PropertyRNA *prop)
static wmOperatorStatus op_generic_value_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void interactive_value_exit(ValueInteraction *inter)
static void op_generic_value_cancel(bContext *, wmOperator *op)
static void interactive_value_init(bContext *C, ValueInteraction *inter, const wmEvent *event, const float value_final, const float range[2])
wmOperatorStatus WM_operator_flag_only_pass_through_on_press(wmOperatorStatus retval, const wmEvent *event)
static void op_generic_value_exit(wmOperator *op)
void WM_operator_type_modal_from_exec_for_object_edit_coords(wmOperatorType *ot)
static bool interactive_value_update(ValueInteraction *inter, const wmEvent *event, float *r_value_final)