Blender V4.3
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
11#include <cmath>
12
13#include "BLI_array.hh"
14#include "BLI_string.h"
15#include "BLI_utildefines.h"
16
17#include "BKE_context.hh"
18#include "BKE_global.hh"
19#include "BKE_layer.hh"
20
21#include "RNA_access.hh"
22#include "RNA_define.hh"
23
24#include "WM_api.hh" /* Own include. */
25#include "WM_types.hh"
26
27#include "MEM_guardedalloc.h"
28
29#include "ED_object.hh"
30#include "ED_screen.hh"
31
32using blender::Array;
33using blender::Vector;
34
35/* -------------------------------------------------------------------- */
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
56/* -------------------------------------------------------------------- */
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
90 inter->context_vars.area = CTX_wm_area(C);
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 = float(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
157/* -------------------------------------------------------------------- */
174
175/* Internal callback to free. */
177{
179 if (cd) {
181
183 if (xod != nullptr) {
185 }
186 }
187 MEM_delete(cd);
188 }
189
190 G.moving &= ~G_TRANSFORM_EDIT;
191}
192
201
203{
205}
206
207static int op_generic_value_invoke(bContext *C, wmOperator *op, const wmEvent *event)
208{
209 if (RNA_property_is_set(op->ptr, op->type->prop)) {
210 return WM_operator_call_notest(C, op);
211 }
212
213 const Scene *scene = CTX_data_scene(C);
214 ViewLayer *view_layer = CTX_data_view_layer(C);
216 scene, view_layer, CTX_wm_view3d(C));
217 if (objects.is_empty()) {
218 return OPERATOR_CANCELLED;
219 }
220
221 ObCustomData_ForEditMode *cd = MEM_new<ObCustomData_ForEditMode>(__func__);
223 cd->wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input");
224 cd->is_active = !cd->wait_for_input;
225 cd->is_first = true;
226
227 if (cd->wait_for_input == false) {
228 interactive_value_init_from_property(C, &cd->inter, event, op->ptr, op->type->prop);
229 }
230
231 cd->objects_xform.reinitialize(objects.size());
232 for (const int i : objects.index_range()) {
233 Object *obedit = objects[i];
235 static_cast<ID *>(obedit->data));
236 }
237
238 op->customdata = cd;
239
241 G.moving |= G_TRANSFORM_EDIT;
242
244}
245
246static int op_generic_value_modal(bContext *C, wmOperator *op, const wmEvent *event)
247{
249
250 /* Special case, check if we release the event that activated this operator. */
251 if ((event->type == cd->launch_event) && (event->val == KM_RELEASE)) {
252 if (cd->wait_for_input == false) {
254 return OPERATOR_FINISHED;
255 }
256 }
257
258 switch (event->type) {
259 case MOUSEMOVE:
260 case EVT_LEFTCTRLKEY:
261 case EVT_RIGHTCTRLKEY:
262 case EVT_LEFTSHIFTKEY:
263 case EVT_RIGHTSHIFTKEY: {
264 float value_final;
265 if (cd->is_active && interactive_value_update(&cd->inter, event, &value_final)) {
267
268 RNA_property_float_set(op->ptr, op->type->prop, value_final);
269 if (cd->is_first == false) {
271 }
272
273 wm->op_undo_depth++;
274 int retval = op->type->exec(C, op);
275 OPERATOR_RETVAL_CHECK(retval);
276 wm->op_undo_depth--;
277
278 cd->is_first = false;
279
280 if ((retval & OPERATOR_FINISHED) == 0) {
282 return OPERATOR_CANCELLED;
283 }
284 }
285 break;
286 }
287 case EVT_RETKEY:
288 case EVT_PADENTER:
289 case LEFTMOUSE: {
290 if (cd->wait_for_input) {
291 if (event->val == KM_PRESS) {
292 if (cd->is_active == false) {
293 cd->is_active = true;
294 interactive_value_init_from_property(C, &cd->inter, event, op->ptr, op->type->prop);
295 }
296 }
297 else if (event->val == KM_RELEASE) {
298 if (cd->is_active == true) {
300 return OPERATOR_FINISHED;
301 }
302 }
303 }
304 else {
305 if (event->val == KM_RELEASE) {
307 return OPERATOR_FINISHED;
308 }
309 }
310 break;
311 }
312 case EVT_ESCKEY:
313 case RIGHTMOUSE: {
314 if (event->val == KM_PRESS) {
315 if (cd->is_active == true) {
317 }
319 return OPERATOR_CANCELLED;
320 }
321 break;
322 }
323 }
325}
326
328{
329 PropertyRNA *prop;
330
331 BLI_assert(ot->modal == nullptr);
332 BLI_assert(ot->invoke == nullptr);
333 BLI_assert(ot->cancel == nullptr);
334 BLI_assert(ot->prop != nullptr);
335
339
340 prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
342}
343
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:50
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
#define OPERATOR_RETVAL_CHECK(ret)
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:803
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
@ KM_CTRL
Definition WM_types.hh:256
@ KM_SHIFT
Definition WM_types.hh:255
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
draw_view in_light_buf[] float
#define str(s)
#define G(x, y, z)
XFormObjectData * data_xform_create_from_edit_mode(ID *id)
void data_xform_destroy(XFormObjectData *xod_base)
void data_xform_tag_update(XFormObjectData *xod)
void data_xform_restore(XFormObjectData *xod)
vector snap(vector a, vector b)
Definition node_math.h:65
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:413
blender::Array< blender::ed::object::XFormObjectData * > objects_xform
struct ValueInteraction::@1382 init
struct ValueInteraction::@1383 prev
struct ValueInteraction::@1384 context_vars
short val
Definition WM_types.hh:724
uint8_t modifier
Definition WM_types.hh:739
short type
Definition WM_types.hh:722
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct wmOperatorType * type
struct PointerRNA * ptr
int WM_userdef_event_type_from_keymap_type(int kmitype)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
int WM_operator_call_notest(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:4126
wmOperatorType * ot
Definition wm_files.cc:4125
static void op_generic_value_restore(wmOperator *op)
static int 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 int op_generic_value_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_operator_flag_only_pass_through_on_press(int retval, 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])
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)