Merge branch 'master' into blender2.8
[blender.git] / source / blender / windowmanager / manipulators / intern / wm_manipulatormap.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  * The Original Code is Copyright (C) 2014 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/windowmanager/manipulators/intern/wm_manipulatormap.c
27  *  \ingroup wm
28  */
29
30 #include <string.h>
31
32 #include "BKE_context.h"
33
34 #include "BLI_listbase.h"
35 #include "BLI_math.h"
36 #include "BLI_string.h"
37 #include "BLI_ghash.h"
38
39 #include "DNA_manipulator_types.h"
40
41 #include "ED_screen.h"
42 #include "ED_view3d.h"
43
44 #include "GPU_glew.h"
45 #include "GPU_matrix.h"
46 #include "GPU_select.h"
47
48 #include "MEM_guardedalloc.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52 #include "wm_event_system.h"
53
54 /* own includes */
55 #include "wm_manipulator_wmapi.h"
56 #include "wm_manipulator_intern.h"
57
58 /**
59  * Store all manipulator-maps here. Anyone who wants to register a manipulator for a certain
60  * area type can query the manipulator-map to do so.
61  */
62 static ListBase manipulatormaptypes = {NULL, NULL};
63
64 /**
65  * Manipulator-map update tagging.
66  */
67 enum eManipulatorMapUpdateFlags {
68         /* Tag manipulator-map for refresh. */
69         MANIPULATORMAP_REFRESH = (1 << 0),
70 };
71
72
73 /* -------------------------------------------------------------------- */
74 /** \name wmManipulatorMap
75  *
76  * \{ */
77
78 /**
79  * Creates a manipulator-map with all registered manipulators for that type
80  */
81 wmManipulatorMap *WM_manipulatormap_new_from_type(const struct wmManipulatorMapType_Params *mmap_params)
82 {
83         wmManipulatorMapType *mmaptype = WM_manipulatormaptype_ensure(mmap_params);
84         wmManipulatorMap *mmap;
85
86         mmap = MEM_callocN(sizeof(wmManipulatorMap), "ManipulatorMap");
87         mmap->type = mmaptype;
88         mmap->update_flag = MANIPULATORMAP_REFRESH;
89
90         /* create all manipulator-groups for this manipulator-map. We may create an empty one
91          * too in anticipation of manipulators from operators etc */
92         for (wmManipulatorGroupType *wgt = mmaptype->manipulator_grouptypes.first; wgt; wgt = wgt->next) {
93                 wm_manipulatorgroup_new_from_type(mmap, wgt);
94         }
95
96         return mmap;
97 }
98
99 void wm_manipulatormap_selected_clear(wmManipulatorMap *mmap)
100 {
101         MEM_SAFE_FREE(mmap->mmap_context.selected);
102         mmap->mmap_context.selected_len = 0;
103 }
104
105 void wm_manipulatormap_remove(wmManipulatorMap *mmap)
106 {
107         if (!mmap)
108                 return;
109
110         for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first, *mgroup_next; mgroup; mgroup = mgroup_next) {
111                 mgroup_next = mgroup->next;
112                 BLI_assert(mgroup->parent_mmap == mmap);
113                 wm_manipulatorgroup_free(NULL, mgroup);
114         }
115         BLI_assert(BLI_listbase_is_empty(&mmap->manipulator_groups));
116
117         wm_manipulatormap_selected_clear(mmap);
118
119         MEM_freeN(mmap);
120 }
121
122 /**
123  * Creates and returns idname hash table for (visible) manipulators in \a mmap
124  *
125  * \param poll  Polling function for excluding manipulators.
126  * \param data  Custom data passed to \a poll
127  */
128 static GHash *WM_manipulatormap_manipulator_hash_new(
129         const bContext *C, wmManipulatorMap *mmap,
130         bool (*poll)(const wmManipulator *, void *),
131         void *data, const bool include_hidden)
132 {
133         GHash *hash = BLI_ghash_str_new(__func__);
134
135         /* collect manipulators */
136         for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) {
137                 if (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type)) {
138                         for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
139                                 if ((include_hidden || (mpr->flag & WM_MANIPULATOR_HIDDEN) == 0) &&
140                                     (!poll || poll(mpr, data)))
141                                 {
142                                         BLI_ghash_insert(hash, mpr->name, mpr);
143                                 }
144                         }
145                 }
146         }
147
148         return hash;
149 }
150
151 void WM_manipulatormap_tag_refresh(wmManipulatorMap *mmap)
152 {
153         if (mmap) {
154                 mmap->update_flag |= MANIPULATORMAP_REFRESH;
155         }
156 }
157
158 static void manipulatormap_tag_updated(wmManipulatorMap *mmap)
159 {
160         mmap->update_flag = 0;
161 }
162
163 static bool manipulator_prepare_drawing(
164         wmManipulatorMap *mmap, wmManipulator *mpr,
165         const bContext *C, ListBase *draw_manipulators)
166 {
167         if (!wm_manipulator_is_visible(mpr)) {
168                 /* skip */
169         }
170         else {
171                 wm_manipulator_update(mpr, C, (mmap->update_flag & MANIPULATORMAP_REFRESH) != 0);
172                 BLI_addhead(draw_manipulators, BLI_genericNodeN(mpr));
173                 return true;
174         }
175
176         return false;
177 }
178
179 /**
180  * Update manipulators of \a mmap to prepare for drawing. Adds all manipulators that
181  * should be drawn to list \a draw_manipulators, note that added items need freeing.
182  */
183 static void manipulatormap_prepare_drawing(
184         wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators, const int drawstep)
185 {
186         if (!mmap || BLI_listbase_is_empty(&mmap->manipulator_groups))
187                 return;
188         wmManipulator *active_manipulator = mmap->mmap_context.active;
189
190         /* only active manipulator needs updating */
191         if (active_manipulator) {
192                 if (manipulator_prepare_drawing(mmap, active_manipulator, C, draw_manipulators)) {
193                         manipulatormap_tag_updated(mmap);
194                 }
195                 /* don't draw any other manipulators */
196                 return;
197         }
198
199         for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) {
200                 /* check group visibility - drawstep first to avoid unnecessary call of group poll callback */
201                 if (!wm_manipulatorgroup_is_visible_in_drawstep(mgroup, drawstep) ||
202                     !wm_manipulatorgroup_is_visible(mgroup, C))
203                 {
204                         continue;
205                 }
206
207                 /* needs to be initialized on first draw */
208                 wm_manipulatorgroup_ensure_initialized(mgroup, C);
209                 /* update data if needed */
210                 /* XXX weak: Manipulator-group may skip refreshing if it's invisible (map gets untagged nevertheless) */
211                 if (mmap->update_flag & MANIPULATORMAP_REFRESH && mgroup->type->refresh) {
212                         mgroup->type->refresh(C, mgroup);
213                 }
214                 /* prepare drawing */
215                 if (mgroup->type->draw_prepare) {
216                         mgroup->type->draw_prepare(C, mgroup);
217                 }
218
219                 for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
220                         manipulator_prepare_drawing(mmap, mpr, C, draw_manipulators);
221                 }
222         }
223
224         manipulatormap_tag_updated(mmap);
225 }
226
227 /**
228  * Draw all visible manipulators in \a mmap.
229  * Uses global draw_manipulators listbase.
230  */
231 static void manipulators_draw_list(const wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators)
232 {
233         if (!mmap)
234                 return;
235         BLI_assert(!BLI_listbase_is_empty(&mmap->manipulator_groups));
236
237         const bool draw_multisample = (U.ogl_multisamples != USER_MULTISAMPLE_NONE);
238
239         /* TODO this will need it own shader probably? don't think it can be handled from that point though. */
240 /*      const bool use_lighting = (U.manipulator_flag & V3D_SHADED_MANIPULATORS) != 0; */
241
242         /* enable multisampling */
243         if (draw_multisample) {
244                 glEnable(GL_MULTISAMPLE);
245         }
246
247         /* draw_manipulators contains all visible manipulators - draw them */
248         for (LinkData *link = draw_manipulators->first, *link_next; link; link = link_next) {
249                 wmManipulator *mpr = link->data;
250                 link_next = link->next;
251
252                 mpr->type->draw(C, mpr);
253                 /* free/remove manipulator link after drawing */
254                 BLI_freelinkN(draw_manipulators, link);
255         }
256
257         if (draw_multisample) {
258                 glDisable(GL_MULTISAMPLE);
259         }
260 }
261
262 void WM_manipulatormap_draw(wmManipulatorMap *mmap, const bContext *C, const int drawstep)
263 {
264         ListBase draw_manipulators = {NULL};
265
266         manipulatormap_prepare_drawing(mmap, C, &draw_manipulators, drawstep);
267         manipulators_draw_list(mmap, C, &draw_manipulators);
268         BLI_assert(BLI_listbase_is_empty(&draw_manipulators));
269 }
270
271 static void manipulator_find_active_3D_loop(const bContext *C, ListBase *visible_manipulators)
272 {
273         int selectionbase = 0;
274         wmManipulator *mpr;
275
276         for (LinkData *link = visible_manipulators->first; link; link = link->next) {
277                 mpr = link->data;
278                 /* pass the selection id shifted by 8 bits. Last 8 bits are used for selected manipulator part id */
279                 mpr->type->draw_select(C, mpr, selectionbase << 8);
280
281                 selectionbase++;
282         }
283 }
284
285 static int manipulator_find_intersected_3d_intern(
286         ListBase *visible_manipulators, const bContext *C, const int co[2],
287         const float hotspot)
288 {
289         ScrArea *sa = CTX_wm_area(C);
290         ARegion *ar = CTX_wm_region(C);
291         View3D *v3d = sa->spacedata.first;
292         rcti rect;
293         /* Almost certainly overkill, but allow for many custom manipulators. */
294         GLuint buffer[MAXPICKBUF];
295         short hits;
296         const bool do_passes = GPU_select_query_check_active();
297
298         rect.xmin = co[0] - hotspot;
299         rect.xmax = co[0] + hotspot;
300         rect.ymin = co[1] - hotspot;
301         rect.ymax = co[1] + hotspot;
302
303         ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_scene(C), ar, v3d, NULL, NULL, &rect);
304
305         if (do_passes)
306                 GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
307         else
308                 GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_ALL, 0);
309         /* do the drawing */
310         manipulator_find_active_3D_loop(C, visible_manipulators);
311
312         hits = GPU_select_end();
313
314         if (do_passes && (hits > 0)) {
315                 GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
316                 manipulator_find_active_3D_loop(C, visible_manipulators);
317                 GPU_select_end();
318         }
319
320         ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_scene(C), ar, v3d, NULL, NULL, NULL);
321
322         return hits > 0 ? buffer[3] : -1;
323 }
324
325 /**
326  * Try to find a 3D manipulator at screen-space coordinate \a co. Uses OpenGL picking.
327  */
328 static wmManipulator *manipulator_find_intersected_3d(
329         bContext *C, const int co[2], ListBase *visible_manipulators,
330         int *r_part)
331 {
332         wmManipulator *result = NULL;
333         const float hotspot = 14.0f;
334         int ret;
335
336         *r_part = 0;
337         /* set up view matrices */
338         view3d_operator_needs_opengl(C);
339
340         ret = manipulator_find_intersected_3d_intern(visible_manipulators, C, co, 0.5f * hotspot);
341
342         if (ret != -1) {
343                 LinkData *link;
344                 int retsec;
345                 retsec = manipulator_find_intersected_3d_intern(visible_manipulators, C, co, 0.2f * hotspot);
346
347                 if (retsec != -1)
348                         ret = retsec;
349
350                 link = BLI_findlink(visible_manipulators, ret >> 8);
351                 *r_part = ret & 255;
352                 result = link->data;
353         }
354
355         return result;
356 }
357
358 /**
359  * Try to find a manipulator under the mouse position. 2D intersections have priority over
360  * 3D ones (could check for smallest screen-space distance but not needed right now).
361  */
362 wmManipulator *wm_manipulatormap_highlight_find(
363         wmManipulatorMap *mmap, bContext *C, const wmEvent *event,
364         int *r_part)
365 {
366         wmManipulator *mpr = NULL;
367         ListBase visible_3d_manipulators = {NULL};
368
369         for (wmManipulatorGroup *mgroup = mmap->manipulator_groups.first; mgroup; mgroup = mgroup->next) {
370                 if (wm_manipulatorgroup_is_visible(mgroup, C)) {
371                         if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) {
372                                 wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators);
373                         }
374                         else if ((mpr = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, r_part))) {
375                                 break;
376                         }
377                 }
378         }
379
380         if (!BLI_listbase_is_empty(&visible_3d_manipulators)) {
381                 mpr = manipulator_find_intersected_3d(C, event->mval, &visible_3d_manipulators, r_part);
382                 BLI_freelistN(&visible_3d_manipulators);
383         }
384
385         return mpr;
386 }
387
388 void WM_manipulatormap_add_handlers(ARegion *ar, wmManipulatorMap *mmap)
389 {
390         wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "manipulator handler");
391
392         BLI_assert(mmap == ar->manipulator_map);
393         handler->manipulator_map = mmap;
394         BLI_addtail(&ar->handlers, handler);
395 }
396
397 void wm_manipulatormaps_handled_modal_update(
398         bContext *C, wmEvent *event, wmEventHandler *handler)
399 {
400         const bool modal_running = (handler->op != NULL);
401
402         /* happens on render or when joining areas */
403         if (!handler->op_region || !handler->op_region->manipulator_map) {
404                 return;
405         }
406
407         wmManipulatorMap *mmap = handler->op_region->manipulator_map;
408         wmManipulator *mpr = wm_manipulatormap_active_get(mmap);
409         ScrArea *area = CTX_wm_area(C);
410         ARegion *region = CTX_wm_region(C);
411
412         wm_manipulatormap_handler_context(C, handler);
413
414         /* regular update for running operator */
415         if (modal_running) {
416                 if (mpr && mpr->opname &&
417                     STREQ(mpr->opname, handler->op->idname))
418                 {
419                         if (mpr->custom_modal) {
420                                 mpr->custom_modal(C, mpr, event, 0);
421                         }
422                         else if (mpr->type->modal) {
423                                 mpr->type->modal(C, mpr, event, 0);
424                         }
425                 }
426         }
427         /* operator not running anymore */
428         else {
429                 wm_manipulatormap_highlight_set(mmap, C, NULL, 0);
430                 wm_manipulatormap_active_set(mmap, C, event, NULL);
431         }
432
433         /* restore the area */
434         CTX_wm_area_set(C, area);
435         CTX_wm_region_set(C, region);
436 }
437
438 /**
439  * Deselect all selected manipulators in \a mmap.
440  * \return if selection has changed.
441  */
442 bool wm_manipulatormap_deselect_all(wmManipulatorMap *mmap, wmManipulator ***sel)
443 {
444         if (*sel == NULL || mmap->mmap_context.selected_len == 0)
445                 return false;
446
447         for (int i = 0; i < mmap->mmap_context.selected_len; i++) {
448                 (*sel)[i]->state &= ~WM_MANIPULATOR_STATE_SELECT;
449                 (*sel)[i] = NULL;
450         }
451         wm_manipulatormap_selected_clear(mmap);
452
453         /* always return true, we already checked
454          * if there's anything to deselect */
455         return true;
456 }
457
458 BLI_INLINE bool manipulator_selectable_poll(const wmManipulator *mpr, void *UNUSED(data))
459 {
460         return (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECT);
461 }
462
463 /**
464  * Select all selectable manipulators in \a mmap.
465  * \return if selection has changed.
466  */
467 static bool wm_manipulatormap_select_all_intern(
468         bContext *C, wmManipulatorMap *mmap, wmManipulator ***sel,
469         const int action)
470 {
471         /* GHash is used here to avoid having to loop over all manipulators twice (once to
472          * get tot_sel for allocating, once for actually selecting). Instead we collect
473          * selectable manipulators in hash table and use this to get tot_sel and do selection */
474
475         GHash *hash = WM_manipulatormap_manipulator_hash_new(C, mmap, manipulator_selectable_poll, NULL, true);
476         GHashIterator gh_iter;
477         int i, *selected_len = &mmap->mmap_context.selected_len;
478         bool changed = false;
479
480         *selected_len = BLI_ghash_size(hash);
481         *sel = MEM_reallocN(*sel, sizeof(**sel) * (*selected_len));
482
483         GHASH_ITER_INDEX (gh_iter, hash, i) {
484                 wmManipulator *mpr_iter = BLI_ghashIterator_getValue(&gh_iter);
485
486                 if ((mpr_iter->state & WM_MANIPULATOR_STATE_SELECT) == 0) {
487                         changed = true;
488                 }
489                 mpr_iter->state |= WM_MANIPULATOR_STATE_SELECT;
490                 if (mpr_iter->type->select) {
491                         mpr_iter->type->select(C, mpr_iter, action);
492                 }
493                 (*sel)[i] = mpr_iter;
494                 BLI_assert(i < (*selected_len));
495         }
496         /* highlight first manipulator */
497         wm_manipulatormap_highlight_set(mmap, C, (*sel)[0], (*sel)[0]->highlight_part);
498
499         BLI_ghash_free(hash, NULL, NULL);
500         return changed;
501 }
502
503 /**
504  * Select/Deselect all selectable manipulators in \a mmap.
505  * \return if selection has changed.
506  *
507  * TODO select all by type
508  */
509 bool WM_manipulatormap_select_all(bContext *C, wmManipulatorMap *mmap, const int action)
510 {
511         wmManipulator ***sel = &mmap->mmap_context.selected;
512         bool changed = false;
513
514         switch (action) {
515                 case SEL_SELECT:
516                         changed = wm_manipulatormap_select_all_intern(C, mmap, sel, action);
517                         break;
518                 case SEL_DESELECT:
519                         changed = wm_manipulatormap_deselect_all(mmap, sel);
520                         break;
521                 default:
522                         BLI_assert(0);
523                         break;
524         }
525
526         if (changed)
527                 WM_event_add_mousemove(C);
528
529         return changed;
530 }
531
532 /**
533  * Prepare context for manipulator handling (but only if area/region is
534  * part of screen). Version of #wm_handler_op_context for manipulators.
535  */
536 void wm_manipulatormap_handler_context(bContext *C, wmEventHandler *handler)
537 {
538         bScreen *screen = CTX_wm_screen(C);
539
540         if (screen) {
541                 if (handler->op_area == NULL) {
542                         /* do nothing in this context */
543                 }
544                 else {
545                         ScrArea *sa;
546
547                         for (sa = screen->areabase.first; sa; sa = sa->next)
548                                 if (sa == handler->op_area)
549                                         break;
550                         if (sa == NULL) {
551                                 /* when changing screen layouts with running modal handlers (like render display), this
552                                  * is not an error to print */
553                                 if (handler->manipulator_map == NULL)
554                                         printf("internal error: modal manipulator-map handler has invalid area\n");
555                         }
556                         else {
557                                 ARegion *ar;
558                                 CTX_wm_area_set(C, sa);
559                                 for (ar = sa->regionbase.first; ar; ar = ar->next)
560                                         if (ar == handler->op_region)
561                                                 break;
562                                 /* XXX no warning print here, after full-area and back regions are remade */
563                                 if (ar)
564                                         CTX_wm_region_set(C, ar);
565                         }
566                 }
567         }
568 }
569
570 bool WM_manipulatormap_cursor_set(const wmManipulatorMap *mmap, wmWindow *win)
571 {
572         for (; mmap; mmap = mmap->next) {
573                 wmManipulator *mpr = mmap->mmap_context.highlight;
574                 if (mpr && mpr->type->cursor_get) {
575                         WM_cursor_set(win, mpr->type->cursor_get(mpr));
576                         return true;
577                 }
578         }
579
580         return false;
581 }
582
583 void wm_manipulatormap_highlight_set(
584         wmManipulatorMap *mmap, const bContext *C, wmManipulator *mpr, int part)
585 {
586         if ((mpr != mmap->mmap_context.highlight) ||
587             (mpr && part != mpr->highlight_part))
588         {
589                 if (mmap->mmap_context.highlight) {
590                         mmap->mmap_context.highlight->state &= ~WM_MANIPULATOR_STATE_HIGHLIGHT;
591                         mmap->mmap_context.highlight->highlight_part = 0;
592                 }
593
594                 mmap->mmap_context.highlight = mpr;
595
596                 if (mpr) {
597                         mpr->state |= WM_MANIPULATOR_STATE_HIGHLIGHT;
598                         mpr->highlight_part = part;
599
600                         if (C && mpr->type->cursor_get) {
601                                 wmWindow *win = CTX_wm_window(C);
602                                 WM_cursor_set(win, mpr->type->cursor_get(mpr));
603                         }
604                 }
605                 else {
606                         if (C) {
607                                 wmWindow *win = CTX_wm_window(C);
608                                 WM_cursor_set(win, CURSOR_STD);
609                         }
610                 }
611
612                 /* tag the region for redraw */
613                 if (C) {
614                         ARegion *ar = CTX_wm_region(C);
615                         ED_region_tag_redraw(ar);
616                 }
617         }
618 }
619
620 wmManipulator *wm_manipulatormap_highlight_get(wmManipulatorMap *mmap)
621 {
622         return mmap->mmap_context.highlight;
623 }
624
625 void wm_manipulatormap_active_set(
626         wmManipulatorMap *mmap, bContext *C, const wmEvent *event, wmManipulator *mpr)
627 {
628         if (mpr && C) {
629                 mpr->state |= WM_MANIPULATOR_STATE_ACTIVE;
630                 mmap->mmap_context.active = mpr;
631
632                 if (mpr->opname) {
633                         wmOperatorType *ot = WM_operatortype_find(mpr->opname, 0);
634
635                         if (ot) {
636                                 /* first activate the manipulator itself */
637                                 if (mpr->type->invoke &&
638                                     (mpr->type->modal || mpr->custom_modal))
639                                 {
640                                         mpr->type->invoke(C, mpr, event);
641                                 }
642
643                                 WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &mpr->opptr);
644
645                                 /* we failed to hook the manipulator to the operator handler or operator was cancelled, return */
646                                 if (!mmap->mmap_context.active) {
647                                         mpr->state &= ~WM_MANIPULATOR_STATE_ACTIVE;
648                                         /* first activate the manipulator itself */
649                                         MEM_SAFE_FREE(mpr->interaction_data);
650                                 }
651                                 return;
652                         }
653                         else {
654                                 printf("Manipulator error: operator not found");
655                                 mmap->mmap_context.active = NULL;
656                                 return;
657                         }
658                 }
659                 else {
660                         if (mpr->type->invoke &&
661                             (mpr->type->modal || mpr->custom_modal))
662                         {
663                                 mpr->type->invoke(C, mpr, event);
664                         }
665                 }
666                 WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL);
667         }
668         else {
669                 mpr = mmap->mmap_context.active;
670
671                 /* deactivate, manipulator but first take care of some stuff */
672                 if (mpr) {
673                         mpr->state &= ~WM_MANIPULATOR_STATE_ACTIVE;
674                         /* first activate the manipulator itself */
675                         MEM_SAFE_FREE(mpr->interaction_data);
676                 }
677                 mmap->mmap_context.active = NULL;
678
679                 if (C) {
680                         WM_cursor_grab_disable(CTX_wm_window(C), NULL);
681                         ED_region_tag_redraw(CTX_wm_region(C));
682                         WM_event_add_mousemove(C);
683                 }
684         }
685 }
686
687 wmManipulator *wm_manipulatormap_active_get(wmManipulatorMap *mmap)
688 {
689         return mmap->mmap_context.active;
690 }
691
692 /** \} */ /* wmManipulatorMap */
693
694
695 /* -------------------------------------------------------------------- */
696 /** \name wmManipulatorMapType
697  *
698  * \{ */
699
700 wmManipulatorMapType *WM_manipulatormaptype_find(
701         const struct wmManipulatorMapType_Params *mmap_params)
702 {
703         for (wmManipulatorMapType *mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) {
704                 if (mmaptype->spaceid == mmap_params->spaceid &&
705                     mmaptype->regionid == mmap_params->regionid &&
706                     STREQ(mmaptype->idname, mmap_params->idname))
707                 {
708                         return mmaptype;
709                 }
710         }
711
712         return NULL;
713 }
714
715 wmManipulatorMapType *WM_manipulatormaptype_ensure(
716         const struct wmManipulatorMapType_Params *mmap_params)
717 {
718         wmManipulatorMapType *mmaptype = WM_manipulatormaptype_find(mmap_params);
719
720         if (mmaptype) {
721                 return mmaptype;
722         }
723
724         mmaptype = MEM_callocN(sizeof(wmManipulatorMapType), "manipulatortype list");
725         mmaptype->spaceid = mmap_params->spaceid;
726         mmaptype->regionid = mmap_params->regionid;
727         BLI_strncpy(mmaptype->idname, mmap_params->idname, sizeof(mmaptype->idname));
728         BLI_addhead(&manipulatormaptypes, mmaptype);
729
730         return mmaptype;
731 }
732
733 void wm_manipulatormaptypes_free(void)
734 {
735         for (wmManipulatorMapType *mmaptype = manipulatormaptypes.first, *mmaptype_next;
736              mmaptype;
737              mmaptype = mmaptype_next)
738         {
739                 mmaptype_next = mmaptype->next;
740                 for (wmManipulatorGroupType *wgt = mmaptype->manipulator_grouptypes.first, *wgt_next;
741                      wgt;
742                      wgt = wgt_next)
743                 {
744                         wgt_next = wgt->next;
745                         WM_manipulatorgrouptype_free(wgt);
746                 }
747                 MEM_freeN(mmaptype);
748         }
749 }
750
751 /**
752  * Initialize keymaps for all existing manipulator-groups
753  */
754 void wm_manipulators_keymap(wmKeyConfig *keyconf)
755 {
756         wmManipulatorMapType *mmaptype;
757         wmManipulatorGroupType *wgt;
758
759         /* we add this item-less keymap once and use it to group manipulator-group keymaps into it */
760         WM_keymap_find(keyconf, "Manipulators", 0, 0);
761
762         for (mmaptype = manipulatormaptypes.first; mmaptype; mmaptype = mmaptype->next) {
763                 for (wgt = mmaptype->manipulator_grouptypes.first; wgt; wgt = wgt->next) {
764                         wm_manipulatorgrouptype_setup_keymap(wgt, keyconf);
765                 }
766         }
767 }
768
769 /** \} */ /* wmManipulatorMapType */
770