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