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) 2016 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup wm
22  *
23  * \name Gizmo Types
24  * \brief Gizmo defines for external use.
25  *
26  * Only included in WM_types.h and lower level files.
27  */
28 
29 #pragma once
30 
31 #include "BLI_compiler_attrs.h"
32 
33 struct wmGizmo;
34 struct wmGizmoGroup;
35 struct wmGizmoGroupType;
36 struct wmGizmoMapType;
37 struct wmGizmoProperty;
38 struct wmKeyConfig;
39 
40 #include "DNA_listBase.h"
41 
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45 
46 /* -------------------------------------------------------------------- */
47 /* Enum Typedef's */
48 
49 /**
50  * #wmGizmo.state
51  */
52 typedef enum eWM_GizmoFlagState {
53   /** While hovered. */
54   WM_GIZMO_STATE_HIGHLIGHT = (1 << 0),
55   /** While dragging. */
56   WM_GIZMO_STATE_MODAL = (1 << 1),
57   WM_GIZMO_STATE_SELECT = (1 << 2),
58 } eWM_GizmoFlagState;
59 
60 /**
61  * #wmGizmo.flag
62  * Flags for individual gizmos.
63  */
64 typedef enum eWM_GizmoFlag {
65   /** Draw *only* while hovering. */
66   WM_GIZMO_DRAW_HOVER = (1 << 0),
67   /** Draw while dragging. */
68   WM_GIZMO_DRAW_MODAL = (1 << 1),
69   /** Draw an indicator for the current value while dragging. */
70   WM_GIZMO_DRAW_VALUE = (1 << 2),
71   WM_GIZMO_HIDDEN = (1 << 3),
72   WM_GIZMO_HIDDEN_SELECT = (1 << 4),
73   /** Ignore the key-map for this gizmo. */
74   WM_GIZMO_HIDDEN_KEYMAP = (1 << 5),
75   /**
76    * When set 'scale_final' value also scales the offset.
77    * Use when offset is to avoid screen-space overlap instead of absolute positioning. */
78   WM_GIZMO_DRAW_OFFSET_SCALE = (1 << 6),
79   /**
80    * User should still use 'scale_final' for any handles and UI elements.
81    * This simply skips scale when calculating the final matrix.
82    * Needed when the gizmo needs to align with the interface underneath it. */
83   WM_GIZMO_DRAW_NO_SCALE = (1 << 7),
84   /**
85    * Hide the cursor and lock its position while interacting with this gizmo.
86    */
87   WM_GIZMO_MOVE_CURSOR = (1 << 8),
88   /** Don't write into the depth buffer when selecting. */
89   WM_GIZMO_SELECT_BACKGROUND = (1 << 9),
90 
91   /** Use the active tools operator properties when running as an operator. */
92   WM_GIZMO_OPERATOR_TOOL_INIT = (1 << 10),
93 
94   /** Don't pass through events to other handlers
95    * (allows click/drag not to have its events stolen by press events in other keymaps). */
96   WM_GIZMO_EVENT_HANDLE_ALL = (1 << 11),
97 
98   /** Don't use tool-tips for this gizmo (can be distracting). */
99   WM_GIZMO_NO_TOOLTIP = (1 << 12),
100 } eWM_GizmoFlag;
101 
102 /**
103  * #wmGizmoGroupType.flag
104  * Flags that influence the behavior of all gizmos in the group.
105  */
106 typedef enum eWM_GizmoFlagGroupTypeFlag {
107   /** Mark gizmo-group as being 3D */
108   WM_GIZMOGROUPTYPE_3D = (1 << 0),
109   /** Scale gizmos as 3D object that respects zoom (otherwise zoom independent draw size).
110    * note: currently only for 3D views, 2D support needs adding. */
111   WM_GIZMOGROUPTYPE_SCALE = (1 << 1),
112   /** Gizmos can be depth culled with scene objects (covered by other geometry - TODO) */
113   WM_GIZMOGROUPTYPE_DEPTH_3D = (1 << 2),
114   /** Gizmos can be selected. */
115   WM_GIZMOGROUPTYPE_SELECT = (1 << 3),
116   /** The gizmo group is to be kept (not removed on loading a new file for eg). */
117   WM_GIZMOGROUPTYPE_PERSISTENT = (1 << 4),
118   /** Show all other gizmos when interacting. */
119   WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL = (1 << 5),
120   /**
121    * When used with tool, only run when activating the tool,
122    * instead of linking the gizmo while the tool is active.
123    *
124    * \warning this option has some limitations, we might even re-implement this differently.
125    * Currently it's quite minimal so we can see how it works out.
126    * The main issue is controlling how a gizmo is activated with a tool
127    * when a tool can activate multiple operators based on the key-map.
128    * We could even move the options into the key-map item.
129    * ~ campbell. */
130   WM_GIZMOGROUPTYPE_TOOL_INIT = (1 << 6),
131 
132   /**
133    * This gizmo type supports using the fallback tools keymap.
134    * #wmGizmoGroup.use_tool_fallback will need to be set too.
135    *
136    * Often useful in combination with #WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK
137    */
138   WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP = (1 << 7),
139 
140   /**
141    * Use this from a gizmos refresh callback so we can postpone the refresh operation
142    * until the tweak operation is finished.
143    * Only do this when the group doesn't have a highlighted gizmo.
144    *
145    * The result for the user is tweak events delay the gizmo from flashing under the users cursor,
146    * for selection operations. This means gizmos that use this check don't interfere
147    * with click drag events by popping up under the cursor and catching the tweak event.
148    */
149   WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK = (1 << 8),
150 
151   /**
152    * Cause continuous redraws, i.e. set the region redraw flag on every main loop iteration. This
153    * should really be avoided by using proper region redraw tagging, notifiers and the message-bus,
154    * however for VR it's sometimes needed.
155    */
156   WM_GIZMOGROUPTYPE_VR_REDRAWS = (1 << 9),
157 } eWM_GizmoFlagGroupTypeFlag;
158 
159 /**
160  * #wmGizmoGroup.init_flag
161  */
162 typedef enum eWM_GizmoFlagGroupInitFlag {
163   /** Gizmo-group has been initialized. */
164   WM_GIZMOGROUP_INIT_SETUP = (1 << 0),
165   WM_GIZMOGROUP_INIT_REFRESH = (1 << 1),
166 } eWM_GizmoFlagGroupInitFlag;
167 
168 /**
169  * #wmGizmoMapType.type_update_flag
170  * Gizmo-map type update flag
171  */
172 typedef enum eWM_GizmoFlagMapTypeUpdateFlag {
173   /** A new type has been added, needs to be initialized for all views. */
174   WM_GIZMOMAPTYPE_UPDATE_INIT = (1 << 0),
175   WM_GIZMOMAPTYPE_UPDATE_REMOVE = (1 << 1),
176 
177   /** Needed because keymap may be registered before and after window initialization.
178    * So we need to keep track of keymap initialization separately. */
179   WM_GIZMOMAPTYPE_KEYMAP_INIT = (1 << 2),
180 } eWM_GizmoFlagMapTypeUpdateFlag;
181 
182 /* -------------------------------------------------------------------- */
183 /* wmGizmo */
184 
185 /**
186  * \brief Gizmo tweak flag.
187  * Bitflag passed to gizmo while tweaking.
188  *
189  * \note Gizmos are responsible for handling this #wmGizmo.modal callback!.
190  */
191 typedef enum {
192   /* Drag with extra precision (Shift). */
193   WM_GIZMO_TWEAK_PRECISE = (1 << 0),
194   /* Drag with snap enabled (Ctrl).  */
195   WM_GIZMO_TWEAK_SNAP = (1 << 1),
196 } eWM_GizmoFlagTweak;
197 
198 #include "wm_gizmo_fn.h"
199 
200 typedef struct wmGizmoOpElem {
201   struct wmOperatorType *type;
202   /** Operator properties if gizmo spawns and controls an operator,
203    * or owner pointer if gizmo spawns and controls a property. */
204   PointerRNA ptr;
205 
206   bool is_redo;
207 } wmGizmoOpElem;
208 
209 /* gizmos are set per region by registering them on gizmo-maps */
210 struct wmGizmo {
211   struct wmGizmo *next, *prev;
212 
213   /** While we don't have a real type, use this to put type-like vars. */
214   const struct wmGizmoType *type;
215 
216   /** Overrides 'type->modal' when set.
217    * Note that this is a workaround, remove if we can. */
218   wmGizmoFnModal custom_modal;
219 
220   /** Pointer back to group this gizmo is in (just for quick access). */
221   struct wmGizmoGroup *parent_gzgroup;
222 
223   /** Optional keymap to use for this gizmo (overrides #wmGizmoGroupType.keymap) */
224   struct wmKeyMap *keymap;
225 
226   void *py_instance;
227 
228   /** Rna pointer to access properties. */
229   struct PointerRNA *ptr;
230 
231   /** Flags that influence the behavior or how the gizmos are drawn. */
232   eWM_GizmoFlag flag;
233   /** State flags (active, highlighted, selected) */
234   eWM_GizmoFlagState state;
235 
236   /** Optional ID for highlighting different parts of this gizmo.
237    * -1 when unset, otherwise a valid index. (Used as index to 'op_data'). */
238   int highlight_part;
239 
240   /**
241    * For gizmos that differentiate between click & drag,
242    * use a different part for any drag events, -1 when unused.
243    */
244   int drag_part;
245 
246   /** Distance to bias this gizmo above others when picking
247    * (in world-space, scaled by the gizmo scale - when used). */
248   float select_bias;
249 
250   /**
251    * Transformation of the gizmo in 2d or 3d space.
252    * - Matrix axis are expected to be unit length (scale is applied after).
253    * - Behavior when axis aren't orthogonal depends on each gizmo.
254    * - Typically the +Z is the primary axis for gizmos to use.
255    * - 'matrix[3]' must be used for location,
256    *   besides this it's up to the gizmos internal code how the
257    *   rotation components are used for drawing and interaction.
258    */
259 
260   /** The space this gizmo is being modified in. */
261   float matrix_space[4][4];
262   /** Transformation of this gizmo. */
263   float matrix_basis[4][4];
264   /** Custom offset from origin. */
265   float matrix_offset[4][4];
266   /** Runtime property, set the scale while drawing on the viewport. */
267   float scale_final;
268   /** User defined scale, in addition to the original one. */
269   float scale_basis;
270   /** User defined width for line drawing. */
271   float line_width;
272   /** Gizmo colors (uses default fallbacks if not defined). */
273   float color[4], color_hi[4];
274 
275   /** Data used during interaction. */
276   void *interaction_data;
277 
278   /** Operator to spawn when activating the gizmo (overrides property editing),
279    * an array of items (aligned with #wmGizmo.highlight_part). */
280   wmGizmoOpElem *op_data;
281   int op_data_len;
282 
283   struct IDProperty *properties;
284 
285   /** Redraw tag. */
286   bool do_draw;
287 
288   /** Temporary data (assume dirty). */
289   union {
290     float f;
291   } temp;
292 
293   /* over alloc target_properties after 'wmGizmoType.struct_size' */
294 };
295 
296 /** Similar to #PropertyElemRNA, but has an identifier. */
297 typedef struct wmGizmoProperty {
298   const struct wmGizmoPropertyType *type;
299 
300   PointerRNA ptr;
301   PropertyRNA *prop;
302   int index;
303 
304   /* Optional functions for converting to/from RNA  */
305   struct {
306     wmGizmoPropertyFnGet value_get_fn;
307     wmGizmoPropertyFnSet value_set_fn;
308     wmGizmoPropertyFnRangeGet range_get_fn;
309     wmGizmoPropertyFnFree free_fn;
310     void *user_data;
311   } custom_func;
312 } wmGizmoProperty;
313 
314 typedef struct wmGizmoPropertyType {
315   struct wmGizmoPropertyType *next, *prev;
316   /** #PropertyType, typically #PROP_FLOAT. */
317   int data_type;
318   int array_length;
319 
320   /* index within 'wmGizmoType' */
321   int index_in_type;
322 
323   /** over alloc. */
324   char idname[0];
325 } wmGizmoPropertyType;
326 
327 /**
328  * Simple utility wrapper for storing a single gizmo as wmGizmoGroup.customdata (which gets freed).
329  */
330 typedef struct wmGizmoWrapper {
331   struct wmGizmo *gizmo;
332 } wmGizmoWrapper;
333 
334 struct wmGizmoMapType_Params {
335   short spaceid;
336   short regionid;
337 };
338 
339 typedef struct wmGizmoType {
340 
341   const char *idname; /* MAX_NAME */
342 
343   /** Set to 'sizeof(wmGizmo)' or larger for instances of this type,
344    * use so we can cant to other types without the hassle of a custom-data pointer. */
345   uint struct_size;
346 
347   /** Initialize struct (calloc'd 'struct_size' region). */
348   wmGizmoFnSetup setup;
349 
350   /** Draw gizmo. */
351   wmGizmoFnDraw draw;
352 
353   /** Determines 3d intersection by rendering the gizmo in a selection routine. */
354   wmGizmoFnDrawSelect draw_select;
355 
356   /** Determine if the mouse intersects with the gizmo.
357    * The calculation should be done in the callback itself, -1 for no selection. */
358   wmGizmoFnTestSelect test_select;
359 
360   /** Handler used by the gizmo. Usually handles interaction tied to a gizmo type. */
361   wmGizmoFnModal modal;
362 
363   /** Gizmo-specific handler to update gizmo attributes based on the property value. */
364   wmGizmoFnPropertyUpdate property_update;
365 
366   /** Returns the final transformation which may be different from the 'matrix',
367    * depending on the gizmo.
368    * Notes:
369    * - Scale isn't applied (wmGizmo.scale/user_scale).
370    * - Offset isn't applied (wmGizmo.matrix_offset).
371    */
372   wmGizmoFnMatrixBasisGet matrix_basis_get;
373 
374   /** Activate a gizmo state when the user clicks on it. */
375   wmGizmoFnInvoke invoke;
376 
377   /** Called when gizmo tweaking is done - used to free data and reset property when canceling. */
378   wmGizmoFnExit exit;
379 
380   wmGizmoFnCursorGet cursor_get;
381 
382   /** Called when gizmo selection state changes. */
383   wmGizmoFnSelectRefresh select_refresh;
384 
385   /** Free data (not the gizmo itself), use when the gizmo allocates its own members. */
386   wmGizmoFnFree free;
387 
388   /** RNA for properties. */
389   struct StructRNA *srna;
390 
391   /** RNA integration. */
392   ExtensionRNA rna_ext;
393 
394   ListBase target_property_defs;
395   int target_property_defs_len;
396 
397 } wmGizmoType;
398 
399 /* -------------------------------------------------------------------- */
400 /* wmGizmoGroup */
401 
402 /** Factory class for a gizmo-group type, gets called every time a new area is spawned. */
403 typedef struct wmGizmoGroupTypeRef {
404   struct wmGizmoGroupTypeRef *next, *prev;
405   struct wmGizmoGroupType *type;
406 } wmGizmoGroupTypeRef;
407 
408 /* factory class for a gizmo-group type, gets called every time a new area is spawned */
409 typedef struct wmGizmoGroupType {
410   const char *idname; /* MAX_NAME */
411   /** Gizmo-group name - displayed in UI (keymap editor). */
412   const char *name;
413   char owner_id[64]; /* MAX_NAME */
414 
415   /** Poll if gizmo-map should be visible. */
416   wmGizmoGroupFnPoll poll;
417   /** Initially create gizmos and set permanent data - stuff you only need to do once. */
418   wmGizmoGroupFnInit setup;
419   /** Refresh data, only called if recreate flag is set (WM_gizmomap_tag_refresh). */
420   wmGizmoGroupFnRefresh refresh;
421   /** Refresh data for drawing, called before each redraw. */
422   wmGizmoGroupFnDrawPrepare draw_prepare;
423   /** Initialize data for before invoke. */
424   wmGizmoGroupFnInvokePrepare invoke_prepare;
425 
426   /** Keymap init callback for this gizmo-group (optional),
427    * will fall back to default tweak keymap when left NULL. */
428   wmGizmoGroupFnSetupKeymap setup_keymap;
429 
430   /** Optionally subscribe to wmMsgBus events,
431    * these are calculated automatically from RNA properties,
432    * only needed if gizmos depend indirectly on properties. */
433   wmGizmoGroupFnMsgBusSubscribe message_subscribe;
434 
435   /** Keymap created with callback from above. */
436   struct wmKeyMap *keymap;
437   /** Only for convenient removal. */
438   struct wmKeyConfig *keyconf;
439 
440   /* Note: currently gizmo-group instances don't store properties,
441    * they're kept in the tool properties. */
442 
443   /** RNA for properties. */
444   struct StructRNA *srna;
445 
446   /** RNA integration. */
447   ExtensionRNA rna_ext;
448 
449   eWM_GizmoFlagGroupTypeFlag flag;
450 
451   /** So we know which group type to update. */
452   eWM_GizmoFlagMapTypeUpdateFlag type_update_flag;
453 
454   /** Same as gizmo-maps, so registering/unregistering goes to the correct region. */
455   struct wmGizmoMapType_Params gzmap_params;
456 
457   /**
458    * Number of #wmGizmoGroup instances.
459    * Decremented when 'tag_remove' is set, or when removed.
460    */
461   int users;
462 
463 } wmGizmoGroupType;
464 
465 typedef struct wmGizmoGroup {
466   struct wmGizmoGroup *next, *prev;
467 
468   struct wmGizmoGroupType *type;
469   ListBase gizmos;
470 
471   struct wmGizmoMap *parent_gzmap;
472 
473   /** Python stores the class instance here. */
474   void *py_instance;
475   /** Errors and warnings storage. */
476   struct ReportList *reports;
477 
478   /** Has the same result as hiding all gizmos individually. */
479   union {
480     /** Reasons for hiding. */
481     struct {
482       uint delay_refresh_for_tweak : 1;
483     };
484     /** All, when we only want to check if any are hidden. */
485     uint any;
486   } hide;
487 
488   bool tag_remove;
489 
490   bool use_fallback_keymap;
491 
492   void *customdata;
493   /** For freeing customdata from above. */
494   void (*customdata_free)(void *);
495   eWM_GizmoFlagGroupInitFlag init_flag;
496 } wmGizmoGroup;
497 
498 /* -------------------------------------------------------------------- */
499 /* wmGizmoMap */
500 
501 /**
502  * Pass a value of this enum to #WM_gizmomap_draw to tell it what to draw.
503  */
504 typedef enum eWM_GizmoFlagMapDrawStep {
505   /** Draw 2D gizmo-groups (#WM_GIZMOGROUPTYPE_3D not set). */
506   WM_GIZMOMAP_DRAWSTEP_2D = 0,
507   /** Draw 3D gizmo-groups (#WM_GIZMOGROUPTYPE_3D set). */
508   WM_GIZMOMAP_DRAWSTEP_3D,
509 } eWM_GizmoFlagMapDrawStep;
510 #define WM_GIZMOMAP_DRAWSTEP_MAX 2
511 
512 #ifdef __cplusplus
513 }
514 #endif
515