1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 */
16
17 /** \file
18 * \ingroup wm
19 */
20
21 #include "BLI_listbase.h"
22 #include "BLI_math.h"
23
24 #include "BKE_context.h"
25
26 #include "MEM_guardedalloc.h"
27
28 #include "RNA_access.h"
29
30 #include "WM_api.h"
31 #include "WM_message.h"
32 #include "WM_types.h"
33
34 #include "wm.h"
35
36 #include "ED_keyframing.h"
37 #include "ED_screen.h"
38 #include "ED_view3d.h"
39
40 /* own includes */
41 #include "wm_gizmo_intern.h"
42 #include "wm_gizmo_wmapi.h"
43
44 /* -------------------------------------------------------------------- */
45 /** \name Property Definition
46 * \{ */
47
wm_gizmo_target_property_array(wmGizmo * gz)48 BLI_INLINE wmGizmoProperty *wm_gizmo_target_property_array(wmGizmo *gz)
49 {
50 return (wmGizmoProperty *)(POINTER_OFFSET(gz, gz->type->struct_size));
51 }
52
WM_gizmo_target_property_array(wmGizmo * gz)53 wmGizmoProperty *WM_gizmo_target_property_array(wmGizmo *gz)
54 {
55 return wm_gizmo_target_property_array(gz);
56 }
57
WM_gizmo_target_property_at_index(wmGizmo * gz,int index)58 wmGizmoProperty *WM_gizmo_target_property_at_index(wmGizmo *gz, int index)
59 {
60 BLI_assert(index < gz->type->target_property_defs_len);
61 BLI_assert(index != -1);
62 wmGizmoProperty *gz_prop_array = wm_gizmo_target_property_array(gz);
63 return &gz_prop_array[index];
64 }
65
WM_gizmo_target_property_find(wmGizmo * gz,const char * idname)66 wmGizmoProperty *WM_gizmo_target_property_find(wmGizmo *gz, const char *idname)
67 {
68 int index = BLI_findstringindex(
69 &gz->type->target_property_defs, idname, offsetof(wmGizmoPropertyType, idname));
70 if (index != -1) {
71 return WM_gizmo_target_property_at_index(gz, index);
72 }
73 return NULL;
74 }
75
WM_gizmo_target_property_def_rna_ptr(wmGizmo * gz,const wmGizmoPropertyType * gz_prop_type,PointerRNA * ptr,PropertyRNA * prop,int index)76 void WM_gizmo_target_property_def_rna_ptr(wmGizmo *gz,
77 const wmGizmoPropertyType *gz_prop_type,
78 PointerRNA *ptr,
79 PropertyRNA *prop,
80 int index)
81 {
82 wmGizmoProperty *gz_prop = WM_gizmo_target_property_at_index(gz, gz_prop_type->index_in_type);
83
84 /* if gizmo evokes an operator we cannot use it for property manipulation */
85 BLI_assert(gz->op_data == NULL);
86 BLI_assert(prop != NULL);
87
88 gz_prop->type = gz_prop_type;
89
90 gz_prop->ptr = *ptr;
91 gz_prop->prop = prop;
92 gz_prop->index = index;
93
94 if (gz->type->property_update) {
95 gz->type->property_update(gz, gz_prop);
96 }
97 }
98
WM_gizmo_target_property_def_rna(wmGizmo * gz,const char * idname,PointerRNA * ptr,const char * propname,int index)99 void WM_gizmo_target_property_def_rna(
100 wmGizmo *gz, const char *idname, PointerRNA *ptr, const char *propname, int index)
101 {
102 const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type, idname);
103 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
104 if (prop == NULL) {
105 RNA_warning("%s: %s.%s not found", __func__, RNA_struct_identifier(ptr->type), propname);
106 }
107 WM_gizmo_target_property_def_rna_ptr(gz, gz_prop_type, ptr, prop, index);
108 }
109
WM_gizmo_target_property_def_func_ptr(wmGizmo * gz,const wmGizmoPropertyType * gz_prop_type,const wmGizmoPropertyFnParams * params)110 void WM_gizmo_target_property_def_func_ptr(wmGizmo *gz,
111 const wmGizmoPropertyType *gz_prop_type,
112 const wmGizmoPropertyFnParams *params)
113 {
114 wmGizmoProperty *gz_prop = WM_gizmo_target_property_at_index(gz, gz_prop_type->index_in_type);
115
116 /* if gizmo evokes an operator we cannot use it for property manipulation */
117 BLI_assert(gz->op_data == NULL);
118
119 gz_prop->type = gz_prop_type;
120
121 gz_prop->custom_func.value_get_fn = params->value_get_fn;
122 gz_prop->custom_func.value_set_fn = params->value_set_fn;
123 gz_prop->custom_func.range_get_fn = params->range_get_fn;
124 gz_prop->custom_func.free_fn = params->free_fn;
125 gz_prop->custom_func.user_data = params->user_data;
126
127 if (gz->type->property_update) {
128 gz->type->property_update(gz, gz_prop);
129 }
130 }
131
WM_gizmo_target_property_def_func(wmGizmo * gz,const char * idname,const wmGizmoPropertyFnParams * params)132 void WM_gizmo_target_property_def_func(wmGizmo *gz,
133 const char *idname,
134 const wmGizmoPropertyFnParams *params)
135 {
136 const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type, idname);
137 WM_gizmo_target_property_def_func_ptr(gz, gz_prop_type, params);
138 }
139
WM_gizmo_target_property_clear_rna_ptr(wmGizmo * gz,const wmGizmoPropertyType * gz_prop_type)140 void WM_gizmo_target_property_clear_rna_ptr(wmGizmo *gz, const wmGizmoPropertyType *gz_prop_type)
141 {
142 wmGizmoProperty *gz_prop = WM_gizmo_target_property_at_index(gz, gz_prop_type->index_in_type);
143
144 /* if gizmo evokes an operator we cannot use it for property manipulation */
145 BLI_assert(gz->op_data == NULL);
146
147 gz_prop->type = NULL;
148
149 gz_prop->ptr = PointerRNA_NULL;
150 gz_prop->prop = NULL;
151 gz_prop->index = -1;
152 }
153
WM_gizmo_target_property_clear_rna(wmGizmo * gz,const char * idname)154 void WM_gizmo_target_property_clear_rna(wmGizmo *gz, const char *idname)
155 {
156 const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type, idname);
157 WM_gizmo_target_property_clear_rna_ptr(gz, gz_prop_type);
158 }
159
160 /** \} */
161
162 /* -------------------------------------------------------------------- */
163 /** \name Property Access
164 * \{ */
165
WM_gizmo_target_property_is_valid_any(wmGizmo * gz)166 bool WM_gizmo_target_property_is_valid_any(wmGizmo *gz)
167 {
168 wmGizmoProperty *gz_prop_array = wm_gizmo_target_property_array(gz);
169 for (int i = 0; i < gz->type->target_property_defs_len; i++) {
170 wmGizmoProperty *gz_prop = &gz_prop_array[i];
171 if (WM_gizmo_target_property_is_valid(gz_prop)) {
172 return true;
173 }
174 }
175 return false;
176 }
177
WM_gizmo_target_property_is_valid(const wmGizmoProperty * gz_prop)178 bool WM_gizmo_target_property_is_valid(const wmGizmoProperty *gz_prop)
179 {
180 return ((gz_prop->prop != NULL) ||
181 (gz_prop->custom_func.value_get_fn && gz_prop->custom_func.value_set_fn));
182 }
183
WM_gizmo_target_property_float_get(const wmGizmo * gz,wmGizmoProperty * gz_prop)184 float WM_gizmo_target_property_float_get(const wmGizmo *gz, wmGizmoProperty *gz_prop)
185 {
186 if (gz_prop->custom_func.value_get_fn) {
187 float value = 0.0f;
188 BLI_assert(gz_prop->type->array_length == 1);
189 gz_prop->custom_func.value_get_fn(gz, gz_prop, &value);
190 return value;
191 }
192
193 if (gz_prop->index == -1) {
194 return RNA_property_float_get(&gz_prop->ptr, gz_prop->prop);
195 }
196 return RNA_property_float_get_index(&gz_prop->ptr, gz_prop->prop, gz_prop->index);
197 }
198
WM_gizmo_target_property_float_set(bContext * C,const wmGizmo * gz,wmGizmoProperty * gz_prop,const float value)199 void WM_gizmo_target_property_float_set(bContext *C,
200 const wmGizmo *gz,
201 wmGizmoProperty *gz_prop,
202 const float value)
203 {
204 if (gz_prop->custom_func.value_set_fn) {
205 BLI_assert(gz_prop->type->array_length == 1);
206 gz_prop->custom_func.value_set_fn(gz, gz_prop, &value);
207 return;
208 }
209
210 /* reset property */
211 if (gz_prop->index == -1) {
212 RNA_property_float_set(&gz_prop->ptr, gz_prop->prop, value);
213 }
214 else {
215 RNA_property_float_set_index(&gz_prop->ptr, gz_prop->prop, gz_prop->index, value);
216 }
217 RNA_property_update(C, &gz_prop->ptr, gz_prop->prop);
218 }
219
WM_gizmo_target_property_float_get_array(const wmGizmo * gz,wmGizmoProperty * gz_prop,float * value)220 void WM_gizmo_target_property_float_get_array(const wmGizmo *gz,
221 wmGizmoProperty *gz_prop,
222 float *value)
223 {
224 if (gz_prop->custom_func.value_get_fn) {
225 gz_prop->custom_func.value_get_fn(gz, gz_prop, value);
226 return;
227 }
228 RNA_property_float_get_array(&gz_prop->ptr, gz_prop->prop, value);
229 }
230
WM_gizmo_target_property_float_set_array(bContext * C,const wmGizmo * gz,wmGizmoProperty * gz_prop,const float * value)231 void WM_gizmo_target_property_float_set_array(bContext *C,
232 const wmGizmo *gz,
233 wmGizmoProperty *gz_prop,
234 const float *value)
235 {
236 if (gz_prop->custom_func.value_set_fn) {
237 gz_prop->custom_func.value_set_fn(gz, gz_prop, value);
238 return;
239 }
240 RNA_property_float_set_array(&gz_prop->ptr, gz_prop->prop, value);
241
242 RNA_property_update(C, &gz_prop->ptr, gz_prop->prop);
243 }
244
WM_gizmo_target_property_float_range_get(const wmGizmo * gz,wmGizmoProperty * gz_prop,float range[2])245 bool WM_gizmo_target_property_float_range_get(const wmGizmo *gz,
246 wmGizmoProperty *gz_prop,
247 float range[2])
248 {
249 if (gz_prop->custom_func.value_get_fn) {
250 if (gz_prop->custom_func.range_get_fn) {
251 gz_prop->custom_func.range_get_fn(gz, gz_prop, range);
252 return true;
253 }
254 return false;
255 }
256
257 float step, precision;
258 RNA_property_float_ui_range(
259 &gz_prop->ptr, gz_prop->prop, &range[0], &range[1], &step, &precision);
260 return true;
261 }
262
WM_gizmo_target_property_array_length(const wmGizmo * UNUSED (gz),wmGizmoProperty * gz_prop)263 int WM_gizmo_target_property_array_length(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop)
264 {
265 if (gz_prop->custom_func.value_get_fn) {
266 return gz_prop->type->array_length;
267 }
268 return RNA_property_array_length(&gz_prop->ptr, gz_prop->prop);
269 }
270
271 /** \} */
272
273 /* -------------------------------------------------------------------- */
274 /** \name Property Define
275 * \{ */
276
WM_gizmotype_target_property_find(const wmGizmoType * gzt,const char * idname)277 const wmGizmoPropertyType *WM_gizmotype_target_property_find(const wmGizmoType *gzt,
278 const char *idname)
279 {
280 return BLI_findstring(&gzt->target_property_defs, idname, offsetof(wmGizmoPropertyType, idname));
281 }
282
WM_gizmotype_target_property_def(wmGizmoType * gzt,const char * idname,int data_type,int array_length)283 void WM_gizmotype_target_property_def(wmGizmoType *gzt,
284 const char *idname,
285 int data_type,
286 int array_length)
287 {
288 wmGizmoPropertyType *mpt;
289
290 BLI_assert(WM_gizmotype_target_property_find(gzt, idname) == NULL);
291
292 const uint idname_size = strlen(idname) + 1;
293 mpt = MEM_callocN(sizeof(wmGizmoPropertyType) + idname_size, __func__);
294 memcpy(mpt->idname, idname, idname_size);
295 mpt->data_type = data_type;
296 mpt->array_length = array_length;
297 mpt->index_in_type = gzt->target_property_defs_len;
298 gzt->target_property_defs_len += 1;
299 BLI_addtail(&gzt->target_property_defs, mpt);
300 }
301
302 /** \} */
303
304 /* -------------------------------------------------------------------- */
305 /** \name Property Utilities
306 * \{ */
307
WM_gizmo_do_msg_notify_tag_refresh(bContext * UNUSED (C),wmMsgSubscribeKey * UNUSED (msg_key),wmMsgSubscribeValue * msg_val)308 void WM_gizmo_do_msg_notify_tag_refresh(bContext *UNUSED(C),
309 wmMsgSubscribeKey *UNUSED(msg_key),
310 wmMsgSubscribeValue *msg_val)
311 {
312 ARegion *region = msg_val->owner;
313 wmGizmoMap *gzmap = msg_val->user_data;
314
315 ED_region_tag_redraw(
316 region); /* Could possibly avoid a full redraw and only tag for editor overlays
317 * redraw in some cases, see #ED_region_tag_redraw_editor_overlays(). */
318 WM_gizmomap_tag_refresh(gzmap);
319 }
320
321 /**
322 * Runs on the "prepare draw" pass,
323 * drawing the region clears.
324 */
WM_gizmo_target_property_subscribe_all(wmGizmo * gz,struct wmMsgBus * mbus,ARegion * region)325 void WM_gizmo_target_property_subscribe_all(wmGizmo *gz, struct wmMsgBus *mbus, ARegion *region)
326 {
327 if (gz->type->target_property_defs_len) {
328 wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz);
329 for (int i = 0; i < gz->type->target_property_defs_len; i++) {
330 wmGizmoProperty *gz_prop = &gz_prop_array[i];
331 if (WM_gizmo_target_property_is_valid(gz_prop)) {
332 if (gz_prop->prop) {
333 WM_msg_subscribe_rna(mbus,
334 &gz_prop->ptr,
335 gz_prop->prop,
336 &(const wmMsgSubscribeValue){
337 .owner = region,
338 .user_data = region,
339 .notify = ED_region_do_msg_notify_tag_redraw,
340 },
341 __func__);
342 WM_msg_subscribe_rna(mbus,
343 &gz_prop->ptr,
344 gz_prop->prop,
345 &(const wmMsgSubscribeValue){
346 .owner = region,
347 .user_data = gz->parent_gzgroup->parent_gzmap,
348 .notify = WM_gizmo_do_msg_notify_tag_refresh,
349 },
350 __func__);
351 }
352 }
353 }
354 }
355 }
356
357 /**
358 * Auto-key function if auto-key is enabled.
359 */
WM_gizmo_target_property_anim_autokey(bContext * C,const wmGizmo * UNUSED (gz),wmGizmoProperty * gz_prop)360 void WM_gizmo_target_property_anim_autokey(bContext *C,
361 const wmGizmo *UNUSED(gz),
362 wmGizmoProperty *gz_prop)
363 {
364 if (gz_prop->prop != NULL) {
365 Scene *scene = CTX_data_scene(C);
366 const float cfra = (float)CFRA;
367 const int index = gz_prop->index == -1 ? 0 : gz_prop->index;
368 ED_autokeyframe_property(C, scene, &gz_prop->ptr, gz_prop->prop, index, cfra);
369 }
370 }
371
372 /** \} */
373