Cleanup: typedef enums
Manipulator enum types are easy to confuse, use typedefs.
This commit is contained in:
parent
54bc49e6f9
commit
2e83897f91
|
@ -235,7 +235,9 @@ static void manipulator_arrow_draw(const bContext *UNUSED(C), wmManipulator *mpr
|
|||
* Calculate arrow offset independent from prop min value,
|
||||
* meaning the range will not be offset by min value first.
|
||||
*/
|
||||
static void manipulator_arrow_modal(bContext *C, wmManipulator *mpr, const wmEvent *event, const int flag)
|
||||
static void manipulator_arrow_modal(
|
||||
bContext *C, wmManipulator *mpr, const wmEvent *event,
|
||||
eWM_ManipulatorTweak tweak_flag)
|
||||
{
|
||||
ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr;
|
||||
ManipulatorInteraction *inter = mpr->interaction_data;
|
||||
|
@ -334,7 +336,7 @@ static void manipulator_arrow_modal(bContext *C, wmManipulator *mpr, const wmEve
|
|||
const int draw_options = RNA_enum_get(arrow->manipulator.ptr, "draw_options");
|
||||
const bool constrained = (draw_options & ED_MANIPULATOR_ARROW_STYLE_CONSTRAINED) != 0;
|
||||
const bool inverted = (draw_options & ED_MANIPULATOR_ARROW_STYLE_INVERTED) != 0;
|
||||
const bool use_precision = (flag & WM_MANIPULATOR_TWEAK_PRECISE) != 0;
|
||||
const bool use_precision = (tweak_flag & WM_MANIPULATOR_TWEAK_PRECISE) != 0;
|
||||
float value = manipulator_value_from_offset(data, inter, ofs_new, constrained, inverted, use_precision);
|
||||
|
||||
WM_manipulator_target_property_value_set(C, mpr, mpr_prop, value);
|
||||
|
|
|
@ -435,7 +435,7 @@ static void manipulator_rect_transform_invoke(
|
|||
|
||||
static void manipulator_rect_transform_modal(
|
||||
bContext *C, wmManipulator *mpr, const wmEvent *event,
|
||||
const int UNUSED(flag))
|
||||
eWM_ManipulatorTweak UNUSED(tweak_flag))
|
||||
{
|
||||
RectTransformInteraction *data = mpr->interaction_data;
|
||||
/* needed here as well in case clamping occurs */
|
||||
|
|
|
@ -71,7 +71,9 @@
|
|||
/* to use custom dials exported to geom_dial_manipulator.c */
|
||||
// #define USE_MANIPULATOR_CUSTOM_DIAL
|
||||
|
||||
static void manipulator_dial_modal(bContext *C, wmManipulator *mpr, const wmEvent *event, const int flag);
|
||||
static void manipulator_dial_modal(
|
||||
bContext *C, wmManipulator *mpr, const wmEvent *event,
|
||||
eWM_ManipulatorTweak tweak_flag);
|
||||
|
||||
typedef struct DialInteraction {
|
||||
float init_mval[2];
|
||||
|
@ -378,7 +380,9 @@ static void manipulator_dial_draw(const bContext *C, wmManipulator *mpr)
|
|||
}
|
||||
}
|
||||
|
||||
static void manipulator_dial_modal(bContext *C, wmManipulator *mpr, const wmEvent *event, const int UNUSED(flag))
|
||||
static void manipulator_dial_modal(
|
||||
bContext *C, wmManipulator *mpr, const wmEvent *event,
|
||||
eWM_ManipulatorTweak UNUSED(tweak_flag))
|
||||
{
|
||||
const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f}; /* coordinate at which the arc drawing will be started */
|
||||
float angle_ofs, angle_delta;
|
||||
|
|
|
@ -63,7 +63,9 @@
|
|||
#include "../manipulator_geometry.h"
|
||||
#include "../manipulator_library_intern.h"
|
||||
|
||||
static void manipulator_grab_modal(bContext *C, wmManipulator *mpr, const wmEvent *event, const int flag);
|
||||
static void manipulator_grab_modal(
|
||||
bContext *C, wmManipulator *mpr, const wmEvent *event,
|
||||
eWM_ManipulatorTweak tweak_flag);
|
||||
|
||||
typedef struct GrabInteraction {
|
||||
float init_mval[2];
|
||||
|
@ -186,7 +188,9 @@ static void manipulator_grab_draw(const bContext *C, wmManipulator *mpr)
|
|||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
static void manipulator_grab_modal(bContext *C, wmManipulator *mpr, const wmEvent *event, const int UNUSED(flag))
|
||||
static void manipulator_grab_modal(
|
||||
bContext *C, wmManipulator *mpr, const wmEvent *event,
|
||||
eWM_ManipulatorTweak UNUSED(tweak_flag))
|
||||
{
|
||||
GrabInteraction *inter = mpr->interaction_data;
|
||||
|
||||
|
|
|
@ -1140,7 +1140,8 @@ static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup)
|
|||
* Custom handler for manipulator widgets
|
||||
*/
|
||||
static void manipulator_modal(
|
||||
bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), const int UNUSED(flag))
|
||||
bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event),
|
||||
eWM_ManipulatorTweak UNUSED(tweak_flag))
|
||||
{
|
||||
const ScrArea *sa = CTX_wm_area(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
|
|
|
@ -168,7 +168,8 @@ BLI_INLINE void manipulator2d_origin_to_region(ARegion *ar, float *r_origin)
|
|||
* Custom handler for manipulator widgets
|
||||
*/
|
||||
static void manipulator2d_modal(
|
||||
bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), const int UNUSED(flag))
|
||||
bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event),
|
||||
eWM_ManipulatorTweak UNUSED(tweak_flag))
|
||||
{
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
float origin[3];
|
||||
|
|
|
@ -136,20 +136,22 @@ static int rna_manipulator_test_select_cb(
|
|||
}
|
||||
|
||||
static void rna_manipulator_modal_cb(
|
||||
struct bContext *C, struct wmManipulator *mpr, const struct wmEvent *event, int tweak)
|
||||
struct bContext *C, struct wmManipulator *mpr, const struct wmEvent *event,
|
||||
eWM_ManipulatorTweak tweak_flag)
|
||||
{
|
||||
extern FunctionRNA rna_Manipulator_modal_func;
|
||||
wmManipulatorGroup *mgroup = mpr->parent_mgroup;
|
||||
PointerRNA mpr_ptr;
|
||||
ParameterList list;
|
||||
FunctionRNA *func;
|
||||
const int tweak_flag_int = tweak_flag;
|
||||
RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
|
||||
/* RNA_struct_find_function(&mpr_ptr, "modal"); */
|
||||
func = &rna_Manipulator_modal_func;
|
||||
RNA_parameter_list_create(&list, &mpr_ptr, func);
|
||||
RNA_parameter_set_lookup(&list, "context", &C);
|
||||
RNA_parameter_set_lookup(&list, "event", &event);
|
||||
RNA_parameter_set_lookup(&list, "tweak", &tweak);
|
||||
RNA_parameter_set_lookup(&list, "tweak", &tweak_flag_int);
|
||||
mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
|
||||
RNA_parameter_list_free(&list);
|
||||
}
|
||||
|
|
|
@ -42,9 +42,6 @@
|
|||
#include "WM_keymap.h"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
|
||||
/* Include external manipulator API's */
|
||||
#include "manipulators/WM_manipulator_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -68,6 +65,7 @@ struct ImBuf;
|
|||
struct ImageFormatData;
|
||||
struct ARegion;
|
||||
struct ScrArea;
|
||||
struct Main;
|
||||
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
struct wmNDOFMotionData;
|
||||
|
|
|
@ -121,6 +121,9 @@ struct ImBuf;
|
|||
#include "wm_event_types.h"
|
||||
#include "manipulators/WM_manipulator_types.h"
|
||||
|
||||
/* Include external manipulator API's */
|
||||
#include "manipulators/WM_manipulator_api.h"
|
||||
|
||||
/* ************** wmOperatorType ************************ */
|
||||
|
||||
/* flag */
|
||||
|
|
|
@ -45,13 +45,86 @@ struct wmManipulator;
|
|||
struct wmManipulatorProperty;
|
||||
struct wmKeyConfig;
|
||||
|
||||
#include "wm_manipulator_fn.h"
|
||||
|
||||
#include "DNA_listBase.h"
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Enum Typedef's */
|
||||
|
||||
|
||||
/**
|
||||
* #wmManipulator.state
|
||||
*/
|
||||
typedef enum eWM_ManipulatorState {
|
||||
WM_MANIPULATOR_STATE_HIGHLIGHT = (1 << 0), /* while hovered */
|
||||
WM_MANIPULATOR_STATE_MODAL = (1 << 1), /* while dragging */
|
||||
WM_MANIPULATOR_STATE_SELECT = (1 << 2),
|
||||
} eWM_ManipulatorState;
|
||||
|
||||
|
||||
/**
|
||||
* #wmManipulator.flag
|
||||
* Flags for individual manipulators.
|
||||
*/
|
||||
typedef enum eWM_ManipulatorFlag {
|
||||
WM_MANIPULATOR_DRAW_HOVER = (1 << 0), /* draw *only* while hovering */
|
||||
WM_MANIPULATOR_DRAW_MODAL = (1 << 1), /* draw while dragging */
|
||||
WM_MANIPULATOR_DRAW_VALUE = (1 << 2), /* draw an indicator for the current value while dragging */
|
||||
WM_MANIPULATOR_HIDDEN = (1 << 3),
|
||||
} eWM_ManipulatorFlag;
|
||||
|
||||
/**
|
||||
* #wmManipulatorGroupType.flag
|
||||
* Flags that influence the behavior of all manipulators in the group.
|
||||
*/
|
||||
typedef enum eWM_ManipulatorGroupTypeFlag {
|
||||
/* Mark manipulator-group as being 3D */
|
||||
WM_MANIPULATORGROUPTYPE_3D = (1 << 0),
|
||||
/* Scale manipulators as 3D object that respects zoom (otherwise zoom independent draw size).
|
||||
* note: currently only for 3D views, 2D support needs adding. */
|
||||
WM_MANIPULATORGROUPTYPE_SCALE = (1 << 1),
|
||||
/* Manipulators can be depth culled with scene objects (covered by other geometry - TODO) */
|
||||
WM_MANIPULATORGROUPTYPE_DEPTH_3D = (1 << 2),
|
||||
/* Manipulators can be selected */
|
||||
WM_MANIPULATORGROUPTYPE_SELECT = (1 << 3),
|
||||
/* The manipulator group is to be kept (not removed on loading a new file for eg). */
|
||||
WM_MANIPULATORGROUPTYPE_PERSISTENT = (1 << 4),
|
||||
/* Show all other manipulators when interacting. */
|
||||
WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL = (1 << 5),
|
||||
} eWM_ManipulatorGroupTypeFlag;
|
||||
|
||||
/**
|
||||
* #wmManipulatorMapType.type_update_flag
|
||||
* Manipulator-map type update flag
|
||||
*/
|
||||
typedef enum eWM_ManipulatorMapTypeUpdateFlag {
|
||||
/* A new type has been added, needs to be initialized for all views. */
|
||||
WM_MANIPULATORMAPTYPE_UPDATE_INIT = (1 << 0),
|
||||
WM_MANIPULATORMAPTYPE_UPDATE_REMOVE = (1 << 1),
|
||||
|
||||
/* Needed because keymap may be registered before and after window initialization.
|
||||
* So we need to keep track of keymap initialization separately. */
|
||||
WM_MANIPULATORMAPTYPE_KEYMAP_INIT = (1 << 2),
|
||||
} eWM_ManipulatorMapTypeUpdateFlag;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulator */
|
||||
|
||||
/**
|
||||
* \brief Manipulator tweak flag.
|
||||
* Bitflag passed to manipulator while tweaking.
|
||||
*
|
||||
* \note Manipulators are responsible for handling this #wmManipulator.modal callback!.
|
||||
*/
|
||||
typedef enum {
|
||||
/* Drag with extra precision (Shift). */
|
||||
WM_MANIPULATOR_TWEAK_PRECISE = (1 << 0),
|
||||
/* Drag with snap enabled (Ctrl). */
|
||||
WM_MANIPULATOR_TWEAK_SNAP = (1 << 1),
|
||||
} eWM_ManipulatorTweak;
|
||||
|
||||
#include "wm_manipulator_fn.h"
|
||||
|
||||
/* manipulators are set per region by registering them on manipulator-maps */
|
||||
struct wmManipulator {
|
||||
struct wmManipulator *next, *prev;
|
||||
|
@ -73,8 +146,10 @@ struct wmManipulator {
|
|||
/* rna pointer to access properties */
|
||||
struct PointerRNA *ptr;
|
||||
|
||||
int flag; /* flags that influence the behavior or how the manipulators are drawn */
|
||||
short state; /* state flags (active, highlighted, selected) */
|
||||
/* flags that influence the behavior or how the manipulators are drawn */
|
||||
eWM_ManipulatorFlag flag;
|
||||
/* state flags (active, highlighted, selected) */
|
||||
eWM_ManipulatorState state;
|
||||
|
||||
/* Optional ID for highlighting different parts of this manipulator. */
|
||||
int highlight_part;
|
||||
|
@ -152,7 +227,6 @@ typedef struct wmManipulatorPropertyType {
|
|||
} wmManipulatorPropertyType;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Simple utility wrapper for storing a single manipulator as wmManipulatorGroup.customdata (which gets freed).
|
||||
*/
|
||||
|
@ -165,36 +239,6 @@ struct wmManipulatorMapType_Params {
|
|||
short regionid;
|
||||
};
|
||||
|
||||
|
||||
/* wmManipulator.flag
|
||||
* Flags for individual manipulators. */
|
||||
enum {
|
||||
WM_MANIPULATOR_DRAW_HOVER = (1 << 0), /* draw *only* while hovering */
|
||||
WM_MANIPULATOR_DRAW_MODAL = (1 << 1), /* draw while dragging */
|
||||
WM_MANIPULATOR_DRAW_VALUE = (1 << 2), /* draw an indicator for the current value while dragging */
|
||||
WM_MANIPULATOR_HIDDEN = (1 << 3),
|
||||
};
|
||||
|
||||
/* wmManipulator.state */
|
||||
enum {
|
||||
WM_MANIPULATOR_STATE_HIGHLIGHT = (1 << 0), /* while hovered */
|
||||
WM_MANIPULATOR_STATE_MODAL = (1 << 1), /* while dragging */
|
||||
WM_MANIPULATOR_STATE_SELECT = (1 << 2),
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Manipulator tweak flag.
|
||||
* Bitflag passed to manipulator while tweaking.
|
||||
*
|
||||
* \note Manipulators are responsible for handling this #wmManipulator.modal callback!.
|
||||
*/
|
||||
enum {
|
||||
/* Drag with extra precision (Shift). */
|
||||
WM_MANIPULATOR_TWEAK_PRECISE = (1 << 0),
|
||||
/* Drag with snap enabled (Ctrl). */
|
||||
WM_MANIPULATOR_TWEAK_SNAP = (1 << 1),
|
||||
};
|
||||
|
||||
typedef struct wmManipulatorType {
|
||||
|
||||
const char *idname; /* MAX_NAME */
|
||||
|
@ -293,10 +337,10 @@ typedef struct wmManipulatorGroupType {
|
|||
/* RNA integration */
|
||||
ExtensionRNA ext;
|
||||
|
||||
int flag;
|
||||
eWM_ManipulatorGroupTypeFlag flag;
|
||||
|
||||
/* eManipulatorMapTypeUpdateFlags (so we know which group type to update) */
|
||||
uchar type_update_flag;
|
||||
/* So we know which group type to update. */
|
||||
eWM_ManipulatorMapTypeUpdateFlag type_update_flag;
|
||||
|
||||
/* same as manipulator-maps, so registering/unregistering goes to the correct region */
|
||||
struct wmManipulatorMapType_Params mmap_params;
|
||||
|
@ -316,44 +360,9 @@ typedef struct wmManipulatorGroup {
|
|||
|
||||
void *customdata;
|
||||
void (*customdata_free)(void *); /* for freeing customdata from above */
|
||||
int flag; /* private */
|
||||
int pad;
|
||||
int init_flag; /* private (C source only) */
|
||||
} wmManipulatorGroup;
|
||||
|
||||
/**
|
||||
* Manipulator-map type update flag: `wmManipulatorMapType.type_update_flag`
|
||||
*/
|
||||
enum eManipulatorMapTypeUpdateFlags {
|
||||
/* A new type has been added, needs to be initialized for all views. */
|
||||
WM_MANIPULATORMAPTYPE_UPDATE_INIT = (1 << 0),
|
||||
WM_MANIPULATORMAPTYPE_UPDATE_REMOVE = (1 << 1),
|
||||
|
||||
/* Needed because keymap may be registered before and after window initialization.
|
||||
* So we need to keep track of keymap initialization separately. */
|
||||
WM_MANIPULATORMAPTYPE_KEYMAP_INIT = (1 << 2),
|
||||
};
|
||||
|
||||
/**
|
||||
* wmManipulatorGroupType.flag
|
||||
* Flags that influence the behavior of all manipulators in the group.
|
||||
*/
|
||||
enum {
|
||||
/* Mark manipulator-group as being 3D */
|
||||
WM_MANIPULATORGROUPTYPE_3D = (1 << 0),
|
||||
/* Scale manipulators as 3D object that respects zoom (otherwise zoom independent draw size).
|
||||
* note: currently only for 3D views, 2D support needs adding. */
|
||||
WM_MANIPULATORGROUPTYPE_SCALE = (1 << 1),
|
||||
/* Manipulators can be depth culled with scene objects (covered by other geometry - TODO) */
|
||||
WM_MANIPULATORGROUPTYPE_DEPTH_3D = (1 << 2),
|
||||
/* Manipulators can be selected */
|
||||
WM_MANIPULATORGROUPTYPE_SELECT = (1 << 3),
|
||||
/* The manipulator group is to be kept (not removed on loading a new file for eg). */
|
||||
WM_MANIPULATORGROUPTYPE_PERSISTENT = (1 << 4),
|
||||
/* Show all other manipulators when interacting. */
|
||||
WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL = (1 << 5),
|
||||
};
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* wmManipulatorMap */
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ void wm_manipulatorgroup_intersectable_manipulators_to_list(const wmManipulatorG
|
|||
void wm_manipulatorgroup_ensure_initialized(wmManipulatorGroup *mgroup, const bContext *C)
|
||||
{
|
||||
/* prepare for first draw */
|
||||
if (UNLIKELY((mgroup->flag & WM_MANIPULATORGROUP_INITIALIZED) == 0)) {
|
||||
if (UNLIKELY((mgroup->init_flag & WM_MANIPULATORGROUP_INITIALIZED) == 0)) {
|
||||
mgroup->type->setup(C, mgroup);
|
||||
|
||||
/* Not ideal, initialize keymap here, needed for RNA runtime generated manipulators. */
|
||||
|
@ -177,7 +177,7 @@ void wm_manipulatorgroup_ensure_initialized(wmManipulatorGroup *mgroup, const bC
|
|||
BLI_assert(wgt->keymap != NULL);
|
||||
}
|
||||
|
||||
mgroup->flag |= WM_MANIPULATORGROUP_INITIALIZED;
|
||||
mgroup->init_flag |= WM_MANIPULATORGROUP_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,8 @@ struct wmManipulatorMap {
|
|||
struct wmManipulatorMapType *type;
|
||||
ListBase groups; /* wmManipulatorGroup */
|
||||
|
||||
char update_flag; /* private, update tagging */
|
||||
/* private, update tagging (enum defined in C source). */
|
||||
char update_flag;
|
||||
|
||||
/**
|
||||
* \brief Manipulator map runtime context
|
||||
|
@ -125,7 +126,7 @@ struct wmManipulatorMapType {
|
|||
ListBase grouptype_refs;
|
||||
|
||||
/* eManipulatorMapTypeUpdateFlags */
|
||||
uchar type_update_flag;
|
||||
eWM_ManipulatorMapTypeUpdateFlag type_update_flag;
|
||||
};
|
||||
|
||||
void wm_manipulatormap_select_array_clear(struct wmManipulatorMap *mmap);
|
||||
|
|
|
@ -64,17 +64,17 @@ static ListBase manipulatormaptypes = {NULL, NULL};
|
|||
* Update when manipulator-map types change.
|
||||
*/
|
||||
/* so operator removal can trigger update */
|
||||
enum {
|
||||
typedef enum eWM_ManipulatorGroupTypeGlobalFlag {
|
||||
WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_INIT = (1 << 0),
|
||||
WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_REMOVE = (1 << 1),
|
||||
};
|
||||
} eWM_ManipulatorGroupTypeGlobalFlag;
|
||||
|
||||
static char wm_mmap_type_update_flag = 0;
|
||||
static eWM_ManipulatorGroupTypeGlobalFlag wm_mmap_type_update_flag = 0;
|
||||
|
||||
/**
|
||||
* Manipulator-map update tagging.
|
||||
*/
|
||||
enum eManipulatorMapUpdateFlags {
|
||||
enum {
|
||||
/* Tag manipulator-map for refresh. */
|
||||
MANIPULATORMAP_REFRESH = (1 << 0),
|
||||
};
|
||||
|
@ -422,7 +422,7 @@ static void manipulator_draw_select_3D_loop(const bContext *C, ListBase *visible
|
|||
|
||||
for (LinkData *link = visible_manipulators->first; link; link = link->next) {
|
||||
mpr = link->data;
|
||||
|
||||
|
||||
bool is_depth = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_DEPTH_3D) != 0;
|
||||
if (is_depth == is_depth_prev) {
|
||||
/* pass */
|
||||
|
|
|
@ -50,7 +50,7 @@ typedef void (*wmManipulatorFnSetup)(struct wmManipulator *);
|
|||
typedef void (*wmManipulatorFnDraw)(const struct bContext *, struct wmManipulator *);
|
||||
typedef void (*wmManipulatorFnDrawSelect)(const struct bContext *, struct wmManipulator *, int);
|
||||
typedef int (*wmManipulatorFnTestSelect)(struct bContext *, struct wmManipulator *, const struct wmEvent *);
|
||||
typedef void (*wmManipulatorFnModal)(struct bContext *, struct wmManipulator *, const struct wmEvent *, const int);
|
||||
typedef void (*wmManipulatorFnModal)(struct bContext *, struct wmManipulator *, const struct wmEvent *, eWM_ManipulatorTweak);
|
||||
typedef void (*wmManipulatorFnPropertyUpdate)(struct wmManipulator *, struct wmManipulatorProperty *);
|
||||
typedef void (*wmManipulatorFnMatrixWorldGet)(struct wmManipulator *, float[4][4]);
|
||||
typedef void (*wmManipulatorFnInvoke)(struct bContext *, struct wmManipulator *, const struct wmEvent *);
|
||||
|
|
Loading…
Reference in New Issue