Cleanup: move WM type registration into own files
[blender.git] / source / blender / windowmanager / intern / wm_operator_type.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/intern/wm_operator_type.c
22  *  \ingroup wm
23  *
24  * Operator Registry.
25  */
26
27 #include "MEM_guardedalloc.h"
28
29 #include "CLG_log.h"
30
31 #include "DNA_ID.h"
32 #include "DNA_screen_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_userdef_types.h"
35 #include "DNA_windowmanager_types.h"
36
37 #include "BLT_translation.h"
38
39 #include "BLI_blenlib.h"
40 #include "BLI_utildefines.h"
41 #include "BLI_ghash.h"
42
43 #include "BKE_context.h"
44 #include "BKE_idprop.h"
45 #include "BKE_library.h"
46
47 #include "RNA_access.h"
48 #include "RNA_define.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "wm.h"
54 #include "wm_event_system.h"
55
56 #define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)")
57
58 static void wm_operatortype_free_macro(wmOperatorType *ot);
59
60 /* -------------------------------------------------------------------- */
61 /** \name Operator Type Registry
62  * \{ */
63
64 static GHash *global_ops_hash = NULL;
65
66 wmOperatorType *WM_operatortype_find(const char *idname, bool quiet)
67 {
68         if (idname[0]) {
69                 wmOperatorType *ot;
70
71                 /* needed to support python style names without the _OT_ syntax */
72                 char idname_bl[OP_MAX_TYPENAME];
73                 WM_operator_bl_idname(idname_bl, idname);
74
75                 ot = BLI_ghash_lookup(global_ops_hash, idname_bl);
76                 if (ot) {
77                         return ot;
78                 }
79
80                 if (!quiet) {
81                         CLOG_INFO(WM_LOG_OPERATORS, 0, "search for unknown operator '%s', '%s'\n", idname_bl, idname);
82                 }
83         }
84         else {
85                 if (!quiet) {
86                         CLOG_INFO(WM_LOG_OPERATORS, 0, "search for empty operator");
87                 }
88         }
89
90         return NULL;
91 }
92
93 /* caller must free */
94 void WM_operatortype_iter(GHashIterator *ghi)
95 {
96         BLI_ghashIterator_init(ghi, global_ops_hash);
97 }
98
99 /* all ops in 1 list (for time being... needs evaluation later) */
100 void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
101 {
102         wmOperatorType *ot;
103
104         ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
105         ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
106         /* Set the default i18n context now, so that opfunc can redefine it if needed! */
107         RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
108         ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
109         opfunc(ot);
110
111         if (ot->name == NULL) {
112                 CLOG_ERROR(WM_LOG_OPERATORS, "Operator '%s' has no name property", ot->idname);
113         }
114
115         /* XXX All ops should have a description but for now allow them not to. */
116         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
117         RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
118
119         BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
120 }
121
122 void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata)
123 {
124         wmOperatorType *ot;
125
126         ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
127         ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
128         /* Set the default i18n context now, so that opfunc can redefine it if needed! */
129         RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
130         ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
131         opfunc(ot, userdata);
132         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
133         RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
134
135         BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
136 }
137
138
139 /* called on initialize WM_exit() */
140 void WM_operatortype_remove_ptr(wmOperatorType *ot)
141 {
142         BLI_assert(ot == WM_operatortype_find(ot->idname, false));
143
144         RNA_struct_free(&BLENDER_RNA, ot->srna);
145
146         if (ot->last_properties) {
147                 IDP_FreeProperty(ot->last_properties);
148                 MEM_freeN(ot->last_properties);
149         }
150
151         if (ot->macro.first)
152                 wm_operatortype_free_macro(ot);
153
154         BLI_ghash_remove(global_ops_hash, ot->idname, NULL, NULL);
155
156         WM_keyconfig_update_operatortype();
157
158         MEM_freeN(ot);
159 }
160
161 bool WM_operatortype_remove(const char *idname)
162 {
163         wmOperatorType *ot = WM_operatortype_find(idname, 0);
164
165         if (ot == NULL)
166                 return false;
167
168         WM_operatortype_remove_ptr(ot);
169
170         return true;
171 }
172
173 /* called on initialize WM_init() */
174 void wm_operatortype_init(void)
175 {
176         /* reserve size is set based on blender default setup */
177         global_ops_hash = BLI_ghash_str_new_ex("wm_operatortype_init gh", 2048);
178 }
179
180 static void operatortype_ghash_free_cb(wmOperatorType *ot)
181 {
182         if (ot->last_properties) {
183                 IDP_FreeProperty(ot->last_properties);
184                 MEM_freeN(ot->last_properties);
185         }
186
187         if (ot->macro.first)
188                 wm_operatortype_free_macro(ot);
189
190         if (ot->ext.srna) /* python operator, allocs own string */
191                 MEM_freeN((void *)ot->idname);
192
193         MEM_freeN(ot);
194 }
195
196 void wm_operatortype_free(void)
197 {
198         BLI_ghash_free(global_ops_hash, NULL, (GHashValFreeFP)operatortype_ghash_free_cb);
199         global_ops_hash = NULL;
200 }
201
202 /** \} */
203
204 /* -------------------------------------------------------------------- */
205 /** \name Operator Macro Type
206  * \{ */
207
208 typedef struct {
209         int retval;
210 } MacroData;
211
212 static void wm_macro_start(wmOperator *op)
213 {
214         if (op->customdata == NULL) {
215                 op->customdata = MEM_callocN(sizeof(MacroData), "MacroData");
216         }
217 }
218
219 static int wm_macro_end(wmOperator *op, int retval)
220 {
221         if (retval & OPERATOR_CANCELLED) {
222                 MacroData *md = op->customdata;
223
224                 if (md->retval & OPERATOR_FINISHED) {
225                         retval |= OPERATOR_FINISHED;
226                         retval &= ~OPERATOR_CANCELLED;
227                 }
228         }
229
230         /* if modal is ending, free custom data */
231         if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
232                 if (op->customdata) {
233                         MEM_freeN(op->customdata);
234                         op->customdata = NULL;
235                 }
236         }
237
238         return retval;
239 }
240
241 /* macro exec only runs exec calls */
242 static int wm_macro_exec(bContext *C, wmOperator *op)
243 {
244         wmOperator *opm;
245         int retval = OPERATOR_FINISHED;
246
247         wm_macro_start(op);
248
249         for (opm = op->macro.first; opm; opm = opm->next) {
250
251                 if (opm->type->exec) {
252                         retval = opm->type->exec(C, opm);
253                         OPERATOR_RETVAL_CHECK(retval);
254
255                         if (retval & OPERATOR_FINISHED) {
256                                 MacroData *md = op->customdata;
257                                 md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
258                         }
259                         else {
260                                 break; /* operator didn't finish, end macro */
261                         }
262                 }
263                 else {
264                         CLOG_WARN(WM_LOG_OPERATORS, "'%s' cant exec macro", opm->type->idname);
265                 }
266         }
267
268         return wm_macro_end(op, retval);
269 }
270
271 static int wm_macro_invoke_internal(bContext *C, wmOperator *op, const wmEvent *event, wmOperator *opm)
272 {
273         int retval = OPERATOR_FINISHED;
274
275         /* start from operator received as argument */
276         for (; opm; opm = opm->next) {
277                 if (opm->type->invoke)
278                         retval = opm->type->invoke(C, opm, event);
279                 else if (opm->type->exec)
280                         retval = opm->type->exec(C, opm);
281
282                 OPERATOR_RETVAL_CHECK(retval);
283
284                 BLI_movelisttolist(&op->reports->list, &opm->reports->list);
285
286                 if (retval & OPERATOR_FINISHED) {
287                         MacroData *md = op->customdata;
288                         md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
289                 }
290                 else {
291                         break; /* operator didn't finish, end macro */
292                 }
293         }
294
295         return wm_macro_end(op, retval);
296 }
297
298 static int wm_macro_invoke(bContext *C, wmOperator *op, const wmEvent *event)
299 {
300         wm_macro_start(op);
301         return wm_macro_invoke_internal(C, op, event, op->macro.first);
302 }
303
304 static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event)
305 {
306         wmOperator *opm = op->opm;
307         int retval = OPERATOR_FINISHED;
308
309         if (opm == NULL) {
310                 CLOG_ERROR(WM_LOG_OPERATORS, "macro error, calling NULL modal()");
311         }
312         else {
313                 retval = opm->type->modal(C, opm, event);
314                 OPERATOR_RETVAL_CHECK(retval);
315
316                 /* if we're halfway through using a tool and cancel it, clear the options [#37149] */
317                 if (retval & OPERATOR_CANCELLED) {
318                         WM_operator_properties_clear(opm->ptr);
319                 }
320
321                 /* if this one is done but it's not the last operator in the macro */
322                 if ((retval & OPERATOR_FINISHED) && opm->next) {
323                         MacroData *md = op->customdata;
324
325                         md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
326
327                         retval = wm_macro_invoke_internal(C, op, event, opm->next);
328
329                         /* if new operator is modal and also added its own handler */
330                         if (retval & OPERATOR_RUNNING_MODAL && op->opm != opm) {
331                                 wmWindow *win = CTX_wm_window(C);
332                                 wmEventHandler *handler;
333
334                                 handler = BLI_findptr(&win->modalhandlers, op, offsetof(wmEventHandler, op));
335                                 if (handler) {
336                                         BLI_remlink(&win->modalhandlers, handler);
337                                         wm_event_free_handler(handler);
338                                 }
339
340                                 /* if operator is blocking, grab cursor
341                                  * This may end up grabbing twice, but we don't care.
342                                  * */
343                                 if (op->opm->type->flag & OPTYPE_BLOCKING) {
344                                         int bounds[4] = {-1, -1, -1, -1};
345                                         const bool wrap = (
346                                                 (U.uiflag & USER_CONTINUOUS_MOUSE) &&
347                                                 ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || (op->opm->type->flag & OPTYPE_GRAB_CURSOR)));
348
349                                         if (wrap) {
350                                                 ARegion *ar = CTX_wm_region(C);
351                                                 if (ar) {
352                                                         bounds[0] = ar->winrct.xmin;
353                                                         bounds[1] = ar->winrct.ymax;
354                                                         bounds[2] = ar->winrct.xmax;
355                                                         bounds[3] = ar->winrct.ymin;
356                                                 }
357                                         }
358
359                                         WM_cursor_grab_enable(win, wrap, false, bounds);
360                                 }
361                         }
362                 }
363         }
364
365         return wm_macro_end(op, retval);
366 }
367
368 static void wm_macro_cancel(bContext *C, wmOperator *op)
369 {
370         /* call cancel on the current modal operator, if any */
371         if (op->opm && op->opm->type->cancel) {
372                 op->opm->type->cancel(C, op->opm);
373         }
374
375         wm_macro_end(op, OPERATOR_CANCELLED);
376 }
377
378 /* Names have to be static for now */
379 wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, int flag)
380 {
381         wmOperatorType *ot;
382         const char *i18n_context;
383
384         if (WM_operatortype_find(idname, true)) {
385                 CLOG_ERROR(WM_LOG_OPERATORS, "operator %s exists, cannot create macro", idname);
386                 return NULL;
387         }
388
389         ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
390         ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
391
392         ot->idname = idname;
393         ot->name = name;
394         ot->description = description;
395         ot->flag = OPTYPE_MACRO | flag;
396
397         ot->exec = wm_macro_exec;
398         ot->invoke = wm_macro_invoke;
399         ot->modal = wm_macro_modal;
400         ot->cancel = wm_macro_cancel;
401         ot->poll = NULL;
402
403         if (!ot->description) /* XXX All ops should have a description but for now allow them not to. */
404                 ot->description = UNDOCUMENTED_OPERATOR_TIP;
405
406         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
407         RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
408         /* Use i18n context from ext.srna if possible (py operators). */
409         i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLT_I18NCONTEXT_OPERATOR_DEFAULT;
410         RNA_def_struct_translation_context(ot->srna, i18n_context);
411         ot->translation_context = i18n_context;
412
413         BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
414
415         return ot;
416 }
417
418 void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata)
419 {
420         wmOperatorType *ot;
421
422         ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
423         ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
424
425         ot->flag = OPTYPE_MACRO;
426         ot->exec = wm_macro_exec;
427         ot->invoke = wm_macro_invoke;
428         ot->modal = wm_macro_modal;
429         ot->cancel = wm_macro_cancel;
430         ot->poll = NULL;
431
432         if (!ot->description)
433                 ot->description = UNDOCUMENTED_OPERATOR_TIP;
434
435         /* Set the default i18n context now, so that opfunc can redefine it if needed! */
436         RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
437         ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
438         opfunc(ot, userdata);
439
440         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
441         RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
442
443         BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
444 }
445
446 wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname)
447 {
448         wmOperatorTypeMacro *otmacro = MEM_callocN(sizeof(wmOperatorTypeMacro), "wmOperatorTypeMacro");
449
450         BLI_strncpy(otmacro->idname, idname, OP_MAX_TYPENAME);
451
452         /* do this on first use, since operatordefinitions might have been not done yet */
453         WM_operator_properties_alloc(&(otmacro->ptr), &(otmacro->properties), idname);
454         WM_operator_properties_sanitize(otmacro->ptr, 1);
455
456         BLI_addtail(&ot->macro, otmacro);
457
458         {
459                 /* operator should always be found but in the event its not. don't segfault */
460                 wmOperatorType *otsub = WM_operatortype_find(idname, 0);
461                 if (otsub) {
462                         RNA_def_pointer_runtime(ot->srna, otsub->idname, otsub->srna,
463                                                 otsub->name, otsub->description);
464                 }
465         }
466
467         return otmacro;
468 }
469
470 static void wm_operatortype_free_macro(wmOperatorType *ot)
471 {
472         wmOperatorTypeMacro *otmacro;
473
474         for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
475                 if (otmacro->ptr) {
476                         WM_operator_properties_free(otmacro->ptr);
477                         MEM_freeN(otmacro->ptr);
478                 }
479         }
480         BLI_freelistN(&ot->macro);
481 }
482
483 /** \} */