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