UI: delay tool label tip display
[blender.git] / source / blender / windowmanager / gizmo / intern / wm_gizmo_map.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/gizmo/intern/wm_gizmo_map.c
27  *  \ingroup wm
28  */
29
30 #include <string.h>
31
32 #include "BLI_listbase.h"
33 #include "BLI_math.h"
34 #include "BLI_rect.h"
35 #include "BLI_string.h"
36 #include "BLI_ghash.h"
37
38 #include "BKE_context.h"
39 #include "BKE_global.h"
40
41 #include "ED_screen.h"
42 #include "ED_select_utils.h"
43 #include "ED_view3d.h"
44
45 #include "GPU_glew.h"
46 #include "GPU_matrix.h"
47 #include "GPU_select.h"
48
49 #include "MEM_guardedalloc.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53 #include "wm_event_system.h"
54
55 /* for tool-tips */
56 #include "UI_interface.h"
57
58 #include "DEG_depsgraph.h"
59
60 /* own includes */
61 #include "wm_gizmo_wmapi.h"
62 #include "wm_gizmo_intern.h"
63
64 /**
65  * Store all gizmo-maps here. Anyone who wants to register a gizmo for a certain
66  * area type can query the gizmo-map to do so.
67  */
68 static ListBase gizmomaptypes = {NULL, NULL};
69
70 /**
71  * Update when gizmo-map types change.
72  */
73 /* so operator removal can trigger update */
74 typedef enum eWM_GizmoFlagGroupTypeGlobalFlag {
75         WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT = (1 << 0),
76         WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE = (1 << 1),
77 } eWM_GizmoFlagGroupTypeGlobalFlag;
78
79 static eWM_GizmoFlagGroupTypeGlobalFlag wm_gzmap_type_update_flag = 0;
80
81 /**
82  * Gizmo-map update tagging.
83  */
84 enum {
85         /** #gizmomap_prepare_drawing has run */
86         GIZMOMAP_IS_PREPARE_DRAW = (1 << 0),
87         GIZMOMAP_IS_REFRESH_CALLBACK = (1 << 1),
88 };
89
90
91 /* -------------------------------------------------------------------- */
92 /** \name wmGizmoMap Selection Array API
93  *
94  * Just handle ``wm_gizmomap_select_array_*``, not flags or callbacks.
95  *
96  * \{ */
97
98 static void wm_gizmomap_select_array_ensure_len_alloc(wmGizmoMap *gzmap, int len)
99 {
100         wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
101         if (len <= msel->len_alloc) {
102                 return;
103         }
104         msel->items = MEM_reallocN(msel->items, sizeof(*msel->items) * len);
105         msel->len_alloc = len;
106 }
107
108 void wm_gizmomap_select_array_clear(wmGizmoMap *gzmap)
109 {
110         wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
111         MEM_SAFE_FREE(msel->items);
112         msel->len = 0;
113         msel->len_alloc = 0;
114 }
115
116 void wm_gizmomap_select_array_shrink(wmGizmoMap *gzmap, int len_subtract)
117 {
118         wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
119         msel->len -= len_subtract;
120         if (msel->len <= 0) {
121                 wm_gizmomap_select_array_clear(gzmap);
122         }
123         else {
124                 if (msel->len < msel->len_alloc / 2) {
125                         msel->items = MEM_reallocN(msel->items, sizeof(*msel->items) * msel->len);
126                         msel->len_alloc = msel->len;
127                 }
128         }
129 }
130
131 void wm_gizmomap_select_array_push_back(wmGizmoMap *gzmap, wmGizmo *gz)
132 {
133         wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
134         BLI_assert(msel->len <= msel->len_alloc);
135         if (msel->len == msel->len_alloc) {
136                 msel->len_alloc = (msel->len + 1) * 2;
137                 msel->items = MEM_reallocN(msel->items, sizeof(*msel->items) * msel->len_alloc);
138         }
139         msel->items[msel->len++] = gz;
140 }
141
142 void wm_gizmomap_select_array_remove(wmGizmoMap *gzmap, wmGizmo *gz)
143 {
144         wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
145         /* remove gizmo from selected_gizmos array */
146         for (int i = 0; i < msel->len; i++) {
147                 if (msel->items[i] == gz) {
148                         for (int j = i; j < (msel->len - 1); j++) {
149                                 msel->items[j] = msel->items[j + 1];
150                         }
151                         wm_gizmomap_select_array_shrink(gzmap, 1);
152                         break;
153                 }
154         }
155
156 }
157
158 /** \} */
159
160
161 /* -------------------------------------------------------------------- */
162 /** \name wmGizmoMap
163  *
164  * \{ */
165
166 /**
167  * Creates a gizmo-map with all registered gizmos for that type
168  */
169 wmGizmoMap *WM_gizmomap_new_from_type(
170         const struct wmGizmoMapType_Params *gzmap_params)
171 {
172         wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(gzmap_params);
173         wmGizmoMap *gzmap;
174
175         gzmap = MEM_callocN(sizeof(wmGizmoMap), "GizmoMap");
176         gzmap->type = gzmap_type;
177         WM_gizmomap_tag_refresh(gzmap);
178
179         /* create all gizmo-groups for this gizmo-map. We may create an empty one
180          * too in anticipation of gizmos from operators etc */
181         for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref; gzgt_ref = gzgt_ref->next) {
182                 wm_gizmogroup_new_from_type(gzmap, gzgt_ref->type);
183         }
184
185         return gzmap;
186 }
187
188 void wm_gizmomap_remove(wmGizmoMap *gzmap)
189 {
190         /* Clear first so further calls don't waste time trying to maintain correct array state. */
191         wm_gizmomap_select_array_clear(gzmap);
192
193         for (wmGizmoGroup *gzgroup = gzmap->groups.first, *gzgroup_next; gzgroup; gzgroup = gzgroup_next) {
194                 gzgroup_next = gzgroup->next;
195                 BLI_assert(gzgroup->parent_gzmap == gzmap);
196                 wm_gizmogroup_free(NULL, gzgroup);
197         }
198         BLI_assert(BLI_listbase_is_empty(&gzmap->groups));
199
200         MEM_freeN(gzmap);
201 }
202
203
204 wmGizmoGroup *WM_gizmomap_group_find(
205         struct wmGizmoMap *gzmap,
206         const char *idname)
207 {
208         wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
209         if (gzgt) {
210                 return WM_gizmomap_group_find_ptr(gzmap, gzgt);
211         }
212         return NULL;
213 }
214
215 wmGizmoGroup *WM_gizmomap_group_find_ptr(
216         struct wmGizmoMap *gzmap,
217         const struct wmGizmoGroupType *gzgt)
218 {
219         for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
220                 if (gzgroup->type == gzgt) {
221                         return gzgroup;
222                 }
223         }
224         return NULL;
225 }
226
227 const ListBase *WM_gizmomap_group_list(wmGizmoMap *gzmap)
228 {
229         return &gzmap->groups;
230 }
231
232 bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap)
233 {
234         return gzmap->gzmap_context.select.len != 0;
235 }
236
237 /**
238  * \note We could use a callback to define bounds, for now just use matrix location.
239  */
240 bool WM_gizmomap_minmax(
241         const wmGizmoMap *gzmap, bool UNUSED(use_hidden), bool use_select,
242         float r_min[3], float r_max[3])
243 {
244         if (use_select) {
245                 int i;
246                 for (i = 0; i < gzmap->gzmap_context.select.len; i++) {
247                         minmax_v3v3_v3(r_min, r_max, gzmap->gzmap_context.select.items[i]->matrix_basis[3]);
248                 }
249                 return i != 0;
250         }
251         else {
252                 bool ok = false;
253                 BLI_assert(!"TODO");
254                 return ok;
255         }
256 }
257
258 /**
259  * Creates and returns idname hash table for (visible) gizmos in \a gzmap
260  *
261  * \param poll  Polling function for excluding gizmos.
262  * \param data  Custom data passed to \a poll
263  *
264  * TODO(campbell): this uses unreliable order,
265  * best we use an iterator function instead of a hash.
266  */
267 static GHash *WM_gizmomap_gizmo_hash_new(
268         const bContext *C, wmGizmoMap *gzmap,
269         bool (*poll)(const wmGizmo *, void *),
270         void *data, const bool include_hidden)
271 {
272         GHash *hash = BLI_ghash_ptr_new(__func__);
273
274         /* collect gizmos */
275         for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
276                 if (WM_gizmo_group_type_poll(C, gzgroup->type)) {
277                         for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
278                                 if ((include_hidden || (gz->flag & WM_GIZMO_HIDDEN) == 0) &&
279                                     (!poll || poll(gz, data)))
280                                 {
281                                         BLI_ghash_insert(hash, gz, gz);
282                                 }
283                         }
284                 }
285         }
286
287         return hash;
288 }
289
290 void WM_gizmomap_tag_refresh(wmGizmoMap *gzmap)
291 {
292         if (gzmap) {
293                 /* We might want only to refresh some, for tag all steps. */
294                 for (int i = 0; i < WM_GIZMOMAP_DRAWSTEP_MAX; i++) {
295                         gzmap->update_flag[i] |= (
296                                 GIZMOMAP_IS_PREPARE_DRAW |
297                                 GIZMOMAP_IS_REFRESH_CALLBACK);
298                 }
299         }
300 }
301
302 static bool gizmo_prepare_drawing(
303         wmGizmoMap *gzmap, wmGizmo *gz,
304         const bContext *C, ListBase *draw_gizmos,
305         const eWM_GizmoFlagMapDrawStep drawstep)
306 {
307         int do_draw = wm_gizmo_is_visible(gz);
308         if (do_draw == 0) {
309                 /* skip */
310         }
311         else {
312                 /* Ensure we get RNA updates */
313                 if (do_draw & WM_GIZMO_IS_VISIBLE_UPDATE) {
314                         /* hover gizmos need updating, even if we don't draw them */
315                         wm_gizmo_update(gz, C, (gzmap->update_flag[drawstep] & GIZMOMAP_IS_PREPARE_DRAW) != 0);
316                 }
317                 if (do_draw & WM_GIZMO_IS_VISIBLE_DRAW) {
318                         BLI_addhead(draw_gizmos, BLI_genericNodeN(gz));
319                 }
320                 return true;
321         }
322
323         return false;
324 }
325
326 /**
327  * Update gizmos of \a gzmap to prepare for drawing. Adds all gizmos that
328  * should be drawn to list \a draw_gizmos, note that added items need freeing.
329  */
330 static void gizmomap_prepare_drawing(
331         wmGizmoMap *gzmap, const bContext *C, ListBase *draw_gizmos,
332         const eWM_GizmoFlagMapDrawStep drawstep)
333 {
334         if (!gzmap || BLI_listbase_is_empty(&gzmap->groups))
335                 return;
336         wmGizmo *gz_modal = gzmap->gzmap_context.modal;
337
338         /* only active gizmo needs updating */
339         if (gz_modal) {
340                 if ((gz_modal->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL) == 0) {
341                         if (wm_gizmogroup_is_visible_in_drawstep(gz_modal->parent_gzgroup, drawstep)) {
342                                 if (gizmo_prepare_drawing(gzmap, gz_modal, C, draw_gizmos, drawstep)) {
343                                         gzmap->update_flag[drawstep] &= ~GIZMOMAP_IS_PREPARE_DRAW;
344                                 }
345                         }
346                         /* don't draw any other gizmos */
347                         return;
348                 }
349         }
350
351         for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
352                 /* check group visibility - drawstep first to avoid unnecessary call of group poll callback */
353                 if (!wm_gizmogroup_is_visible_in_drawstep(gzgroup, drawstep) ||
354                     !WM_gizmo_group_type_poll(C, gzgroup->type))
355                 {
356                         continue;
357                 }
358
359                 /* needs to be initialized on first draw */
360                 /* XXX weak: Gizmo-group may skip refreshing if it's invisible (map gets untagged nevertheless) */
361                 if (gzmap->update_flag[drawstep] & GIZMOMAP_IS_REFRESH_CALLBACK) {
362                         /* force refresh again. */
363                         gzgroup->init_flag &= ~WM_GIZMOGROUP_INIT_REFRESH;
364                 }
365                 /* Calls `setup`, `setup_keymap` and `refresh` if they're defined. */
366                 wm_gizmogroup_ensure_initialized(gzgroup, C);
367
368                 /* prepare drawing */
369                 if (gzgroup->type->draw_prepare) {
370                         gzgroup->type->draw_prepare(C, gzgroup);
371                 }
372
373                 for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
374                         gizmo_prepare_drawing(gzmap, gz, C, draw_gizmos, drawstep);
375                 }
376         }
377
378         gzmap->update_flag[drawstep] &=
379                 ~(GIZMOMAP_IS_REFRESH_CALLBACK |
380                   GIZMOMAP_IS_PREPARE_DRAW);
381 }
382
383 /**
384  * Draw all visible gizmos in \a gzmap.
385  * Uses global draw_gizmos listbase.
386  */
387 static void gizmos_draw_list(const wmGizmoMap *gzmap, const bContext *C, ListBase *draw_gizmos)
388 {
389         /* Can be empty if we're dynamically added and removed. */
390         if ((gzmap == NULL) || BLI_listbase_is_empty(&gzmap->groups)) {
391                 return;
392         }
393
394         /* TODO this will need it own shader probably? don't think it can be handled from that point though. */
395 /*      const bool use_lighting = (U.gizmo_flag & V3D_GIZMO_SHADED) != 0; */
396
397         bool is_depth_prev = false;
398
399         /* draw_gizmos contains all visible gizmos - draw them */
400         for (LinkData *link = draw_gizmos->first, *link_next; link; link = link_next) {
401                 wmGizmo *gz = link->data;
402                 link_next = link->next;
403
404                 bool is_depth = (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_DEPTH_3D) != 0;
405
406                 /* Weak! since we don't 100% support depth yet (select ignores depth) always show highlighted */
407                 if (is_depth && (gz->state & WM_GIZMO_STATE_HIGHLIGHT)) {
408                         is_depth = false;
409                 }
410
411                 if (is_depth == is_depth_prev) {
412                         /* pass */
413                 }
414                 else {
415                         if (is_depth) {
416                                 glEnable(GL_DEPTH_TEST);
417                         }
418                         else {
419                                 glDisable(GL_DEPTH_TEST);
420                         }
421                         is_depth_prev = is_depth;
422                 }
423
424                 /* XXX force AntiAlias Gizmos. */
425                 glEnable(GL_LINE_SMOOTH);
426                 glEnable(GL_POLYGON_SMOOTH);
427
428                 gz->type->draw(C, gz);
429
430                 glDisable(GL_LINE_SMOOTH);
431                 glDisable(GL_POLYGON_SMOOTH);
432
433                 /* free/remove gizmo link after drawing */
434                 BLI_freelinkN(draw_gizmos, link);
435         }
436
437         if (is_depth_prev) {
438                 glDisable(GL_DEPTH_TEST);
439         }
440 }
441
442 void WM_gizmomap_draw(
443         wmGizmoMap *gzmap, const bContext *C,
444         const eWM_GizmoFlagMapDrawStep drawstep)
445 {
446         if (!WM_gizmo_context_check_drawstep(C, drawstep)) {
447                 return;
448         }
449
450         ListBase draw_gizmos = {NULL};
451
452         gizmomap_prepare_drawing(gzmap, C, &draw_gizmos, drawstep);
453         gizmos_draw_list(gzmap, C, &draw_gizmos);
454         BLI_assert(BLI_listbase_is_empty(&draw_gizmos));
455 }
456
457 static void gizmo_draw_select_3D_loop(
458         const bContext *C, ListBase *visible_gizmos,
459         const wmGizmo *gz_stop)
460 {
461         int select_id = 0;
462         wmGizmo *gz;
463
464         /* TODO(campbell): this depends on depth buffer being written to, currently broken for the 3D view. */
465         bool is_depth_prev = false;
466         bool is_depth_skip_prev = false;
467
468         for (LinkData *link = visible_gizmos->first; link; link = link->next, select_id++) {
469                 gz = link->data;
470                 if (gz == gz_stop) {
471                         break;
472                 }
473                 if (gz->type->draw_select == NULL) {
474                         continue;
475                 }
476
477                 bool is_depth = (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_DEPTH_3D) != 0;
478                 if (is_depth == is_depth_prev) {
479                         /* pass */
480                 }
481                 else {
482                         if (is_depth) {
483                                 glEnable(GL_DEPTH_TEST);
484                         }
485                         else {
486                                 glDisable(GL_DEPTH_TEST);
487                         }
488                         is_depth_prev = is_depth;
489                 }
490                 bool is_depth_skip = (gz->flag & WM_GIZMO_SELECT_BACKGROUND) != 0;
491                 if (is_depth_skip == is_depth_skip_prev) {
492                         /* pass */
493                 }
494                 else {
495                         glDepthMask(!is_depth_skip);
496                         is_depth_skip_prev = is_depth_skip;
497                 }
498
499                 /* pass the selection id shifted by 8 bits. Last 8 bits are used for selected gizmo part id */
500
501                 gz->type->draw_select(C, gz, select_id << 8);
502         }
503
504         if (is_depth_prev) {
505                 glDisable(GL_DEPTH_TEST);
506         }
507         if (is_depth_skip_prev) {
508                 glDepthMask(true);
509         }
510 }
511
512 static int gizmo_find_intersected_3d_intern(
513         ListBase *visible_gizmos, const bContext *C, const int co[2],
514         const int hotspot, const wmGizmo *gz_stop)
515 {
516         ScrArea *sa = CTX_wm_area(C);
517         ARegion *ar = CTX_wm_region(C);
518         View3D *v3d = sa->spacedata.first;
519         rcti rect;
520         /* Almost certainly overkill, but allow for many custom gizmos. */
521         GLuint buffer[MAXPICKBUF];
522         short hits;
523         const bool do_passes = GPU_select_query_check_active();
524
525         BLI_rcti_init_pt_radius(&rect, co, hotspot);
526
527         ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_depsgraph(C), CTX_data_scene(C), ar, v3d, NULL, NULL, &rect);
528
529         if (do_passes)
530                 GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
531         else
532                 GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_ALL, 0);
533         /* do the drawing */
534         gizmo_draw_select_3D_loop(C, visible_gizmos, gz_stop);
535
536         hits = GPU_select_end();
537
538         if (do_passes && (hits > 0)) {
539                 GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
540                 gizmo_draw_select_3D_loop(C, visible_gizmos, gz_stop);
541                 GPU_select_end();
542         }
543
544         ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_depsgraph(C), CTX_data_scene(C), ar, v3d, NULL, NULL, NULL);
545
546         const GLuint *hit_near = GPU_select_buffer_near(buffer, hits);
547
548         return hit_near ? hit_near[3] : -1;
549 }
550
551 /**
552  * Try to find a 3D gizmo at screen-space coordinate \a co. Uses OpenGL picking.
553  */
554 static wmGizmo *gizmo_find_intersected_3d(
555         bContext *C, const int co[2], ListBase *visible_gizmos,
556         int *r_part)
557 {
558         wmGizmo *result = NULL;
559         int hit = -1;
560
561         *r_part = 0;
562
563         /* set up view matrices */
564         view3d_operator_needs_opengl(C);
565
566         /* Search for 3D gizmo's that use the 2D callback for checking intersections. */
567         bool has_3d = false;
568         {
569                 int select_id = 0;
570                 for (LinkData *link = visible_gizmos->first; link; link = link->next, select_id++) {
571                         wmGizmo *gz = link->data;
572                         if (gz->type->test_select) {
573                                 if ((*r_part = gz->type->test_select(C, gz, co)) != -1) {
574                                         hit = select_id;
575                                         result = gz;
576                                         break;
577                                 }
578                         }
579                         else {
580                                 has_3d = true;
581                         }
582                 }
583         }
584
585         /* Search for 3D intersections if they're before 2D that have been found (if any).
586          * This way we always use the first hit. */
587         if (has_3d) {
588                 const int hotspot_radii[] = {
589                         3 * U.pixelsize,
590                         /* This runs on mouse move, careful doing too many tests! */
591                         10 * U.pixelsize,
592                 };
593                 for (int i = 0; i < ARRAY_SIZE(hotspot_radii); i++) {
594                         hit = gizmo_find_intersected_3d_intern(visible_gizmos, C, co, hotspot_radii[i], result);
595                         if (hit != -1) {
596                                 break;
597                         }
598                 }
599
600                 if (hit != -1) {
601                         LinkData *link = BLI_findlink(visible_gizmos, hit >> 8);
602                         if (link != NULL) {
603                                 *r_part = hit & 255;
604                                 result = link->data;
605                         }
606                         else {
607                                 /* All gizmos should use selection ID they're given as part of the callback,
608                                  * if they don't it will attempt tp lookup non-existing index. */
609                                 BLI_assert(0);
610                         }
611                 }
612         }
613
614         return result;
615 }
616
617 /**
618  * Try to find a gizmo under the mouse position. 2D intersections have priority over
619  * 3D ones (could check for smallest screen-space distance but not needed right now).
620  */
621 wmGizmo *wm_gizmomap_highlight_find(
622         wmGizmoMap *gzmap, bContext *C, const wmEvent *event,
623         int *r_part)
624 {
625         wmGizmo *gz = NULL;
626         ListBase visible_3d_gizmos = {NULL};
627         bool do_step[WM_GIZMOMAP_DRAWSTEP_MAX];
628
629         for (int i = 0; i < ARRAY_SIZE(do_step); i++) {
630                 do_step[i] = WM_gizmo_context_check_drawstep(C, i);
631         }
632
633         for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
634
635                 /* If it were important we could initialize here,
636                  * but this only happens when events are handled before drawing,
637                  * just skip to keep code-path for initializing gizmos simple. */
638                 if ((gzgroup->init_flag & WM_GIZMOGROUP_INIT_SETUP) == 0) {
639                         continue;
640                 }
641
642                 if (WM_gizmo_group_type_poll(C, gzgroup->type)) {
643                         eWM_GizmoFlagMapDrawStep step;
644                         if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
645                                 step = WM_GIZMOMAP_DRAWSTEP_3D;
646                         }
647                         else {
648                                 step = WM_GIZMOMAP_DRAWSTEP_2D;
649                         }
650
651                         if (do_step[step]) {
652                                 if ((gzmap->update_flag[step] & GIZMOMAP_IS_REFRESH_CALLBACK) &&
653                                     (gzgroup->type->refresh != NULL))
654                                 {
655                                         gzgroup->type->refresh(C, gzgroup);
656                                         /* cleared below */
657                                 }
658                                 if (step == WM_GIZMOMAP_DRAWSTEP_3D) {
659                                         wm_gizmogroup_intersectable_gizmos_to_list(gzgroup, &visible_3d_gizmos);
660                                 }
661                                 else if (step == WM_GIZMOMAP_DRAWSTEP_2D) {
662                                         if ((gz = wm_gizmogroup_find_intersected_gizmo(gzgroup, C, event, r_part))) {
663                                                 break;
664                                         }
665                                 }
666                         }
667                 }
668         }
669
670         if (!BLI_listbase_is_empty(&visible_3d_gizmos)) {
671                 /* 2D gizmos get priority. */
672                 if (gz == NULL) {
673                         gz = gizmo_find_intersected_3d(C, event->mval, &visible_3d_gizmos, r_part);
674                 }
675                 BLI_freelistN(&visible_3d_gizmos);
676         }
677
678         gzmap->update_flag[WM_GIZMOMAP_DRAWSTEP_3D] &= ~GIZMOMAP_IS_REFRESH_CALLBACK;
679         gzmap->update_flag[WM_GIZMOMAP_DRAWSTEP_2D] &= ~GIZMOMAP_IS_REFRESH_CALLBACK;
680
681         return gz;
682 }
683
684 void WM_gizmomap_add_handlers(ARegion *ar, wmGizmoMap *gzmap)
685 {
686         wmEventHandler *handler;
687
688         for (handler = ar->handlers.first; handler; handler = handler->next) {
689                 if (handler->gizmo_map == gzmap) {
690                         return;
691                 }
692         }
693
694         handler = MEM_callocN(sizeof(wmEventHandler), "gizmo handler");
695
696         BLI_assert(gzmap == ar->gizmo_map);
697         handler->gizmo_map = gzmap;
698         BLI_addtail(&ar->handlers, handler);
699 }
700
701 void wm_gizmomaps_handled_modal_update(
702         bContext *C, wmEvent *event, wmEventHandler *handler)
703 {
704         const bool modal_running = (handler->op != NULL);
705
706         /* happens on render or when joining areas */
707         if (!handler->op_region || !handler->op_region->gizmo_map) {
708                 return;
709         }
710
711         wmGizmoMap *gzmap = handler->op_region->gizmo_map;
712         wmGizmo *gz = wm_gizmomap_modal_get(gzmap);
713         ScrArea *area = CTX_wm_area(C);
714         ARegion *region = CTX_wm_region(C);
715
716         wm_gizmomap_handler_context(C, handler);
717
718         /* regular update for running operator */
719         if (modal_running) {
720                 wmGizmoOpElem *mpop = gz ? WM_gizmo_operator_get(gz, gz->highlight_part) : NULL;
721                 if (gz && mpop && (mpop->type != NULL) && (mpop->type == handler->op->type)) {
722                         wmGizmoFnModal modal_fn = gz->custom_modal ? gz->custom_modal : gz->type->modal;
723                         if (modal_fn != NULL) {
724                                 int retval = modal_fn(C, gz, event, 0);
725                                 /* The gizmo is tried to the operator, we can't choose when to exit. */
726                                 BLI_assert(retval & OPERATOR_RUNNING_MODAL);
727                                 UNUSED_VARS_NDEBUG(retval);
728                         }
729                 }
730         }
731         /* operator not running anymore */
732         else {
733                 wm_gizmomap_highlight_set(gzmap, C, NULL, 0);
734                 if (gz) {
735                         /* This isn't defined if it ends because of success of cancel, we may want to change. */
736                         bool cancel = true;
737                         if (gz->type->exit) {
738                                 gz->type->exit(C, gz, cancel);
739                         }
740                         wm_gizmomap_modal_set(gzmap, C, gz, NULL, false);
741                 }
742         }
743
744         /* restore the area */
745         CTX_wm_area_set(C, area);
746         CTX_wm_region_set(C, region);
747 }
748
749 /**
750  * Deselect all selected gizmos in \a gzmap.
751  * \return if selection has changed.
752  */
753 bool wm_gizmomap_deselect_all(wmGizmoMap *gzmap)
754 {
755         wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
756
757         if (msel->items == NULL || msel->len == 0) {
758                 return false;
759         }
760
761         for (int i = 0; i < msel->len; i++) {
762                 wm_gizmo_select_set_ex(gzmap, msel->items[i], false, false, true);
763         }
764
765         wm_gizmomap_select_array_clear(gzmap);
766
767         /* always return true, we already checked
768          * if there's anything to deselect */
769         return true;
770 }
771
772 BLI_INLINE bool gizmo_selectable_poll(const wmGizmo *gz, void *UNUSED(data))
773 {
774         return (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_SELECT);
775 }
776
777 /**
778  * Select all selectable gizmos in \a gzmap.
779  * \return if selection has changed.
780  */
781 static bool wm_gizmomap_select_all_intern(
782         bContext *C, wmGizmoMap *gzmap)
783 {
784         wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
785         /* GHash is used here to avoid having to loop over all gizmos twice (once to
786          * get tot_sel for allocating, once for actually selecting). Instead we collect
787          * selectable gizmos in hash table and use this to get tot_sel and do selection */
788
789         GHash *hash = WM_gizmomap_gizmo_hash_new(C, gzmap, gizmo_selectable_poll, NULL, true);
790         GHashIterator gh_iter;
791         int i;
792         bool changed = false;
793
794         wm_gizmomap_select_array_ensure_len_alloc(gzmap, BLI_ghash_len(hash));
795
796         GHASH_ITER_INDEX (gh_iter, hash, i) {
797                 wmGizmo *gz_iter = BLI_ghashIterator_getValue(&gh_iter);
798                 WM_gizmo_select_set(gzmap, gz_iter, true);
799         }
800         /* highlight first gizmo */
801         wm_gizmomap_highlight_set(gzmap, C, msel->items[0], msel->items[0]->highlight_part);
802
803         BLI_assert(BLI_ghash_len(hash) == msel->len);
804
805         BLI_ghash_free(hash, NULL, NULL);
806         return changed;
807 }
808
809 /**
810  * Select/Deselect all selectable gizmos in \a gzmap.
811  * \return if selection has changed.
812  *
813  * TODO select all by type
814  */
815 bool WM_gizmomap_select_all(bContext *C, wmGizmoMap *gzmap, const int action)
816 {
817         bool changed = false;
818
819         switch (action) {
820                 case SEL_SELECT:
821                         changed = wm_gizmomap_select_all_intern(C, gzmap);
822                         break;
823                 case SEL_DESELECT:
824                         changed = wm_gizmomap_deselect_all(gzmap);
825                         break;
826                 default:
827                         BLI_assert(0);
828                         break;
829         }
830
831         if (changed)
832                 WM_event_add_mousemove(C);
833
834         return changed;
835 }
836
837 /**
838  * Prepare context for gizmo handling (but only if area/region is
839  * part of screen). Version of #wm_handler_op_context for gizmos.
840  */
841 void wm_gizmomap_handler_context(bContext *C, wmEventHandler *handler)
842 {
843         bScreen *screen = CTX_wm_screen(C);
844
845         if (screen) {
846                 if (handler->op_area == NULL) {
847                         /* do nothing in this context */
848                 }
849                 else {
850                         ScrArea *sa;
851
852                         for (sa = screen->areabase.first; sa; sa = sa->next)
853                                 if (sa == handler->op_area)
854                                         break;
855                         if (sa == NULL) {
856                                 /* when changing screen layouts with running modal handlers (like render display), this
857                                  * is not an error to print */
858                                 if (handler->gizmo_map == NULL)
859                                         printf("internal error: modal gizmo-map handler has invalid area\n");
860                         }
861                         else {
862                                 ARegion *ar;
863                                 CTX_wm_area_set(C, sa);
864                                 for (ar = sa->regionbase.first; ar; ar = ar->next)
865                                         if (ar == handler->op_region)
866                                                 break;
867                                 /* XXX no warning print here, after full-area and back regions are remade */
868                                 if (ar)
869                                         CTX_wm_region_set(C, ar);
870                         }
871                 }
872         }
873 }
874
875 bool WM_gizmomap_cursor_set(const wmGizmoMap *gzmap, wmWindow *win)
876 {
877         wmGizmo *gz = gzmap->gzmap_context.highlight;
878         if (gz && gz->type->cursor_get) {
879                 WM_cursor_set(win, gz->type->cursor_get(gz));
880                 return true;
881         }
882
883         return false;
884 }
885
886 bool wm_gizmomap_highlight_set(
887         wmGizmoMap *gzmap, const bContext *C, wmGizmo *gz, int part)
888 {
889         if ((gz != gzmap->gzmap_context.highlight) ||
890             (gz && part != gz->highlight_part))
891         {
892                 if (gzmap->gzmap_context.highlight) {
893                         gzmap->gzmap_context.highlight->state &= ~WM_GIZMO_STATE_HIGHLIGHT;
894                         gzmap->gzmap_context.highlight->highlight_part = -1;
895                 }
896
897                 gzmap->gzmap_context.highlight = gz;
898
899                 if (gz) {
900                         gz->state |= WM_GIZMO_STATE_HIGHLIGHT;
901                         gz->highlight_part = part;
902                         gzmap->gzmap_context.last_cursor = -1;
903
904                         if (C && gz->type->cursor_get) {
905                                 wmWindow *win = CTX_wm_window(C);
906                                 gzmap->gzmap_context.last_cursor = win->cursor;
907                                 WM_cursor_set(win, gz->type->cursor_get(gz));
908                         }
909                 }
910                 else {
911                         if (C && gzmap->gzmap_context.last_cursor != -1) {
912                                 wmWindow *win = CTX_wm_window(C);
913                                 WM_cursor_set(win, gzmap->gzmap_context.last_cursor);
914                         }
915                 }
916
917                 /* tag the region for redraw */
918                 if (C) {
919                         ARegion *ar = CTX_wm_region(C);
920                         ED_region_tag_redraw(ar);
921                 }
922
923                 return true;
924         }
925
926         return false;
927 }
928
929 wmGizmo *wm_gizmomap_highlight_get(wmGizmoMap *gzmap)
930 {
931         return gzmap->gzmap_context.highlight;
932 }
933
934 /**
935  * Caller should call exit when (enable == False).
936  */
937 void wm_gizmomap_modal_set(
938         wmGizmoMap *gzmap, bContext *C, wmGizmo *gz, const wmEvent *event, bool enable)
939 {
940         if (enable) {
941                 BLI_assert(gzmap->gzmap_context.modal == NULL);
942                 wmWindow *win = CTX_wm_window(C);
943
944                 WM_tooltip_clear(C, win);
945
946                 if (gz->type->invoke &&
947                     (gz->type->modal || gz->custom_modal))
948                 {
949                         const int retval = gz->type->invoke(C, gz, event);
950                         if ((retval & OPERATOR_RUNNING_MODAL) == 0) {
951                                 return;
952                         }
953                 }
954
955                 gz->state |= WM_GIZMO_STATE_MODAL;
956                 gzmap->gzmap_context.modal = gz;
957
958                 if ((gz->flag & WM_GIZMO_GRAB_CURSOR) &&
959                     (event->is_motion_absolute == false))
960                 {
961                         WM_cursor_grab_enable(win, true, true, NULL);
962                         copy_v2_v2_int(gzmap->gzmap_context.event_xy, &event->x);
963                         gzmap->gzmap_context.event_grabcursor = win->grabcursor;
964                 }
965                 else {
966                         gzmap->gzmap_context.event_xy[0] = INT_MAX;
967                 }
968
969                 struct wmGizmoOpElem *mpop = WM_gizmo_operator_get(gz, gz->highlight_part);
970                 if (mpop && mpop->type) {
971                         const int retval = WM_operator_name_call_ptr(C, mpop->type, WM_OP_INVOKE_DEFAULT, &mpop->ptr);
972                         if ((retval & OPERATOR_RUNNING_MODAL) == 0) {
973                                 wm_gizmomap_modal_set(gzmap, C, gz, event, false);
974                         }
975
976                         /* we failed to hook the gizmo to the operator handler or operator was cancelled, return */
977                         if (!gzmap->gzmap_context.modal) {
978                                 gz->state &= ~WM_GIZMO_STATE_MODAL;
979                                 MEM_SAFE_FREE(gz->interaction_data);
980                         }
981                         return;
982                 }
983         }
984         else {
985                 BLI_assert(ELEM(gzmap->gzmap_context.modal, NULL, gz));
986
987                 /* deactivate, gizmo but first take care of some stuff */
988                 if (gz) {
989                         gz->state &= ~WM_GIZMO_STATE_MODAL;
990                         MEM_SAFE_FREE(gz->interaction_data);
991                 }
992                 gzmap->gzmap_context.modal = NULL;
993
994                 if (C) {
995                         wmWindow *win = CTX_wm_window(C);
996                         if (gzmap->gzmap_context.event_xy[0] != INT_MAX) {
997                                 /* Check if some other part of Blender (typically operators)
998                                  * have adjusted the grab mode since it was set.
999                                  * If so: warp, so we have a predictable outcome. */
1000                                 if (gzmap->gzmap_context.event_grabcursor == win->grabcursor) {
1001                                         WM_cursor_grab_disable(win, gzmap->gzmap_context.event_xy);
1002                                 }
1003                                 else {
1004                                         WM_cursor_warp(win, UNPACK2(gzmap->gzmap_context.event_xy));
1005                                 }
1006                         }
1007                         ED_region_tag_redraw(CTX_wm_region(C));
1008                         WM_event_add_mousemove(C);
1009                 }
1010
1011                 gzmap->gzmap_context.event_xy[0] = INT_MAX;
1012         }
1013 }
1014
1015 wmGizmo *wm_gizmomap_modal_get(wmGizmoMap *gzmap)
1016 {
1017         return gzmap->gzmap_context.modal;
1018 }
1019
1020 wmGizmo **wm_gizmomap_selected_get(wmGizmoMap *gzmap, int *r_selected_len)
1021 {
1022         *r_selected_len = gzmap->gzmap_context.select.len;
1023         return gzmap->gzmap_context.select.items;
1024 }
1025
1026 ListBase *wm_gizmomap_groups_get(wmGizmoMap *gzmap)
1027 {
1028         return &gzmap->groups;
1029 }
1030
1031 void WM_gizmomap_message_subscribe(
1032         bContext *C, wmGizmoMap *gzmap, ARegion *ar, struct wmMsgBus *mbus)
1033 {
1034         for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
1035                 if (!WM_gizmo_group_type_poll(C, gzgroup->type)) {
1036                         continue;
1037                 }
1038                 for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
1039                         if (gz->flag & WM_GIZMO_HIDDEN) {
1040                                 continue;
1041                         }
1042                         WM_gizmo_target_property_subscribe_all(gz, mbus, ar);
1043                 }
1044                 if (gzgroup->type->message_subscribe != NULL) {
1045                         gzgroup->type->message_subscribe(C, gzgroup, mbus);
1046                 }
1047         }
1048 }
1049
1050 /** \} */ /* wmGizmoMap */
1051
1052
1053 /* -------------------------------------------------------------------- */
1054 /** \name Tooltip Handling
1055  *
1056  * \{ */
1057
1058 struct ARegion *WM_gizmomap_tooltip_init(
1059         struct bContext *C, struct ARegion *ar, int *UNUSED(r_pass), double *UNUSED(pass_delay), bool *r_exit_on_event)
1060 {
1061         wmGizmoMap *gzmap = ar->gizmo_map;
1062         *r_exit_on_event = true;
1063         if (gzmap) {
1064                 wmGizmo *gz = gzmap->gzmap_context.highlight;
1065                 if (gz) {
1066                         return UI_tooltip_create_from_gizmo(C, gz);
1067                 }
1068         }
1069         return NULL;
1070 }
1071
1072 /** \} */ /* wmGizmoMapType */
1073
1074 /* -------------------------------------------------------------------- */
1075 /** \name wmGizmoMapType
1076  *
1077  * \{ */
1078
1079 wmGizmoMapType *WM_gizmomaptype_find(
1080         const struct wmGizmoMapType_Params *gzmap_params)
1081 {
1082         for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type; gzmap_type = gzmap_type->next) {
1083                 if (gzmap_type->spaceid == gzmap_params->spaceid &&
1084                     gzmap_type->regionid == gzmap_params->regionid)
1085                 {
1086                         return gzmap_type;
1087                 }
1088         }
1089
1090         return NULL;
1091 }
1092
1093 wmGizmoMapType *WM_gizmomaptype_ensure(
1094         const struct wmGizmoMapType_Params *gzmap_params)
1095 {
1096         wmGizmoMapType *gzmap_type = WM_gizmomaptype_find(gzmap_params);
1097
1098         if (gzmap_type) {
1099                 return gzmap_type;
1100         }
1101
1102         gzmap_type = MEM_callocN(sizeof(wmGizmoMapType), "gizmotype list");
1103         gzmap_type->spaceid = gzmap_params->spaceid;
1104         gzmap_type->regionid = gzmap_params->regionid;
1105         BLI_addhead(&gizmomaptypes, gzmap_type);
1106
1107         return gzmap_type;
1108 }
1109
1110 void wm_gizmomaptypes_free(void)
1111 {
1112         for (wmGizmoMapType *gzmap_type = gizmomaptypes.first, *gzmap_type_next;
1113              gzmap_type;
1114              gzmap_type = gzmap_type_next)
1115         {
1116                 gzmap_type_next = gzmap_type->next;
1117                 for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first, *gzgt_next;
1118                      gzgt_ref;
1119                      gzgt_ref = gzgt_next)
1120                 {
1121                         gzgt_next = gzgt_ref->next;
1122                         WM_gizmomaptype_group_free(gzgt_ref);
1123                 }
1124                 MEM_freeN(gzmap_type);
1125         }
1126 }
1127
1128 /**
1129  * Initialize keymaps for all existing gizmo-groups
1130  */
1131 void wm_gizmos_keymap(wmKeyConfig *keyconf)
1132 {
1133         /* we add this item-less keymap once and use it to group gizmo-group keymaps into it */
1134         WM_keymap_ensure(keyconf, "Gizmos", 0, 0);
1135
1136         for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type; gzmap_type = gzmap_type->next) {
1137                 for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref; gzgt_ref = gzgt_ref->next) {
1138                         wm_gizmogrouptype_setup_keymap(gzgt_ref->type, keyconf);
1139                 }
1140         }
1141 }
1142
1143 /** \} */ /* wmGizmoMapType */
1144
1145 /* -------------------------------------------------------------------- */
1146 /** \name Updates for Dynamic Type Registraion
1147  *
1148  * \{ */
1149
1150
1151 void WM_gizmoconfig_update_tag_init(
1152         wmGizmoMapType *gzmap_type, wmGizmoGroupType *gzgt)
1153 {
1154         /* tag for update on next use */
1155         gzmap_type->type_update_flag |= (WM_GIZMOMAPTYPE_UPDATE_INIT | WM_GIZMOMAPTYPE_KEYMAP_INIT);
1156         gzgt->type_update_flag |= (WM_GIZMOMAPTYPE_UPDATE_INIT | WM_GIZMOMAPTYPE_KEYMAP_INIT);
1157
1158         wm_gzmap_type_update_flag |= WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT;
1159 }
1160
1161 void WM_gizmoconfig_update_tag_remove(
1162         wmGizmoMapType *gzmap_type, wmGizmoGroupType *gzgt)
1163 {
1164         /* tag for update on next use */
1165         gzmap_type->type_update_flag |= WM_GIZMOMAPTYPE_UPDATE_REMOVE;
1166         gzgt->type_update_flag |= WM_GIZMOMAPTYPE_UPDATE_REMOVE;
1167
1168         wm_gzmap_type_update_flag |= WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE;
1169 }
1170
1171 /**
1172  * Run incase new types have been added (runs often, early exit where possible).
1173  * Follows #WM_keyconfig_update concentions.
1174  */
1175 void WM_gizmoconfig_update(struct Main *bmain)
1176 {
1177         if (G.background)
1178                 return;
1179
1180         if (wm_gzmap_type_update_flag == 0)
1181                 return;
1182
1183         if (wm_gzmap_type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE) {
1184                 for (wmGizmoMapType *gzmap_type = gizmomaptypes.first;
1185                      gzmap_type;
1186                      gzmap_type = gzmap_type->next)
1187                 {
1188                         if (gzmap_type->type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE) {
1189                                 gzmap_type->type_update_flag &= ~WM_GIZMOMAPTYPE_UPDATE_REMOVE;
1190                                 for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first, *gzgt_ref_next;
1191                                      gzgt_ref;
1192                                      gzgt_ref = gzgt_ref_next)
1193                                 {
1194                                         gzgt_ref_next = gzgt_ref->next;
1195                                         if (gzgt_ref->type->type_update_flag & WM_GIZMOMAPTYPE_UPDATE_REMOVE) {
1196                                                 gzgt_ref->type->type_update_flag &= ~WM_GIZMOMAPTYPE_UPDATE_REMOVE;
1197                                                 WM_gizmomaptype_group_unlink(NULL, bmain, gzmap_type, gzgt_ref->type);
1198                                         }
1199                                 }
1200                         }
1201                 }
1202
1203                 wm_gzmap_type_update_flag &= ~WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE;
1204         }
1205
1206         if (wm_gzmap_type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT) {
1207                 for (wmGizmoMapType *gzmap_type = gizmomaptypes.first;
1208                      gzmap_type;
1209                      gzmap_type = gzmap_type->next)
1210                 {
1211                         const uchar type_update_all = WM_GIZMOMAPTYPE_UPDATE_INIT | WM_GIZMOMAPTYPE_KEYMAP_INIT;
1212                         if (gzmap_type->type_update_flag & type_update_all) {
1213                                 gzmap_type->type_update_flag &= ~type_update_all;
1214                                 for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first;
1215                                      gzgt_ref;
1216                                      gzgt_ref = gzgt_ref->next)
1217                                 {
1218                                         if (gzgt_ref->type->type_update_flag & WM_GIZMOMAPTYPE_KEYMAP_INIT) {
1219                                                 WM_gizmomaptype_group_init_runtime_keymap(bmain, gzgt_ref->type);
1220                                                 gzgt_ref->type->type_update_flag &= ~WM_GIZMOMAPTYPE_KEYMAP_INIT;
1221                                         }
1222
1223                                         if (gzgt_ref->type->type_update_flag & WM_GIZMOMAPTYPE_UPDATE_INIT) {
1224                                                 WM_gizmomaptype_group_init_runtime(bmain, gzmap_type, gzgt_ref->type);
1225                                                 gzgt_ref->type->type_update_flag &= ~WM_GIZMOMAPTYPE_UPDATE_INIT;
1226                                         }
1227                                 }
1228                         }
1229                 }
1230
1231                 wm_gzmap_type_update_flag &= ~WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT;
1232         }
1233 }
1234
1235 /** \} */