View 3D: new utility to provide navigation in operators

Implements a new API consisting of:
- `ED_view3d_navigation_init`,
- `ED_view3d_navigation_do` and
- `ED_view3d_navigation_free`,

With these functions, any operator can create their own navigation
context and navigate in the 3D View without having to use
`PASS_THROUGH`.
This commit is contained in:
Germano Cavalcante
2023-05-19 15:24:55 -03:00
parent 552c262cee
commit 2ce365efc7
5 changed files with 173 additions and 1 deletions

View File

@@ -43,6 +43,7 @@ struct SnapObjectContext;
struct View3D;
struct ViewContext;
struct ViewLayer;
struct ViewOpsData;
struct bContext;
struct bPoseChannel;
struct bScreen;
@@ -210,6 +211,19 @@ bool ED_view3d_depth_unproject_v3(const struct ARegion *region,
double depth,
float r_location_world[3]);
/**
* Utilities to perform navigation.
* Call `ED_view3d_navigation_init` to create a context and `ED_view3d_navigation_do` to perform
* navigation in modal operators.
*
* \note modal map events can also be used in `ED_view3d_navigation_do`.
*/
struct ViewOpsData *ED_view3d_navigation_init(struct bContext *C);
bool ED_view3d_navigation_do(struct bContext *C,
struct ViewOpsData *vod,
const struct wmEvent *event);
void ED_view3d_navigation_free(struct bContext *C, struct ViewOpsData *vod);
/* Projection */
#define IS_CLIPPED 12000

View File

@@ -74,6 +74,8 @@ const char *viewops_operator_idname_get(eV3D_OpMode nav_type)
case V3D_OP_MODE_NDOF_ORBIT_ZOOM:
return "VIEW3D_OT_ndof_orbit_zoom";
#endif
case V3D_OP_MODE_NONE:
break;
}
BLI_assert(false);
return nullptr;
@@ -1942,3 +1944,142 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Navigation Utilities
* \{ */
/* Detect the navigation operation, by the name of the navigation operator (obtained by
* `wmKeyMapItem::idname`) */
static eV3D_OpMode view3d_navigation_type_from_idname(const char *idname)
{
const char *op_name = idname + sizeof("VIEW3D_OT_");
for (int i = 0; i < V3D_OP_MODE_LEN; i++) {
if (STREQ(op_name, viewops_operator_idname_get((eV3D_OpMode)i) + sizeof("VIEW3D_OT_"))) {
return (eV3D_OpMode)i;
}
}
return V3D_OP_MODE_NONE;
}
/* Unlike `viewops_data_create`, `ED_view3d_navigation_init` creates a navigation context along
* with an array of `wmKeyMapItem`s used for navigation. */
ViewOpsData *ED_view3d_navigation_init(bContext *C)
{
if (!CTX_wm_region_view3d(C)) {
return NULL;
}
ViewOpsData *vod = MEM_cnew<ViewOpsData>(__func__);
viewops_data_init_context(C, vod);
vod->keymap = WM_keymap_find_all(CTX_wm_manager(C), "3D View", SPACE_VIEW3D, 0);
return vod;
}
/* Checks and initializes the navigation modal operation. */
static int view3d_navigation_invoke(bContext *C,
ViewOpsData *vod,
const wmEvent *event,
struct wmKeyMapItem *kmi,
eV3D_OpMode nav_type)
{
switch (nav_type) {
case V3D_OP_MODE_ZOOM:
if (!view3d_zoom_or_dolly_poll(C)) {
return OPERATOR_CANCELLED;
}
break;
case V3D_OP_MODE_MOVE:
case V3D_OP_MODE_VIEW_PAN:
if (!view3d_location_poll(C)) {
return OPERATOR_CANCELLED;
}
break;
case V3D_OP_MODE_ROTATE:
if (!view3d_rotation_poll(C)) {
return OPERATOR_CANCELLED;
}
break;
case V3D_OP_MODE_VIEW_ROLL:
case V3D_OP_MODE_DOLLY:
#ifdef WITH_INPUT_NDOF
case V3D_OP_MODE_NDOF_ORBIT:
case V3D_OP_MODE_NDOF_ORBIT_ZOOM:
#endif
case V3D_OP_MODE_NONE:
break;
}
return view3d_navigation_invoke_generic(C, vod, event, kmi->ptr, nav_type);
}
bool ED_view3d_navigation_do(bContext *C, ViewOpsData *vod, const wmEvent *event)
{
if (!vod) {
return false;
}
wmEvent event_tmp;
if (event->type == EVT_MODAL_MAP) {
/* Workaround to use the original event values. */
event_tmp = *event;
event_tmp.type = event->prev_type;
event_tmp.val = event->prev_val;
event = &event_tmp;
}
int op_return = OPERATOR_CANCELLED;
if (vod->is_modal_event) {
const eV3D_OpEvent event_code = view3d_navigate_event(vod, event);
op_return = view3d_navigation_modal(C, vod, event_code, event->xy);
if (op_return != OPERATOR_RUNNING_MODAL) {
viewops_data_end_navigation(C, vod);
vod->is_modal_event = false;
}
}
else {
eV3D_OpMode nav_type;
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &vod->keymap->items) {
if (!STRPREFIX(kmi->idname, "VIEW3D")) {
continue;
}
if (kmi->flag & KMI_INACTIVE) {
continue;
}
if ((nav_type = view3d_navigation_type_from_idname(kmi->idname)) == V3D_OP_MODE_NONE) {
continue;
}
if (!WM_event_match(event, kmi)) {
continue;
}
op_return = view3d_navigation_invoke(C, vod, event, kmi, nav_type);
if (op_return == OPERATOR_RUNNING_MODAL) {
vod->is_modal_event = true;
}
else {
viewops_data_end_navigation(C, vod);
}
break;
}
}
if (op_return != OPERATOR_CANCELLED) {
/* Although #ED_view3d_update_viewmat is already called when redrawing the 3D View, do it here
* as well, so the updated matrix values can be accessed by the operator. */
ED_view3d_update_viewmat(
vod->depsgraph, vod->scene, vod->v3d, vod->region, NULL, NULL, NULL, false);
return true;
}
return false;
}
void ED_view3d_navigation_free(bContext *C, ViewOpsData *vod)
{
viewops_data_free(C, vod);
}
/** \} */

View File

@@ -33,6 +33,7 @@ struct wmEvent;
struct wmOperator;
typedef enum eV3D_OpMode {
V3D_OP_MODE_NONE = -1,
V3D_OP_MODE_ZOOM = 0,
V3D_OP_MODE_ROTATE,
V3D_OP_MODE_MOVE,
@@ -44,6 +45,11 @@ typedef enum eV3D_OpMode {
V3D_OP_MODE_NDOF_ORBIT_ZOOM,
#endif
} eV3D_OpMode;
#ifndef WITH_INPUT_NDOF
# define V3D_OP_MODE_LEN V3D_OP_MODE_DOLLY + 1
#else
# define V3D_OP_MODE_LEN V3D_OP_MODE_NDOF_ORBIT_ZOOM + 1
#endif
enum eV3D_OpPropFlag {
V3D_OP_PROP_MOUSE_CO = (1 << 0),
@@ -179,6 +185,10 @@ typedef struct ViewOpsData {
* See #view3d_orbit_apply_dyn_ofs code-comments for an example, also see: #104385.
*/
bool use_dyn_ofs_ortho_correction;
/** Used for navigation on non view3d operators. */
wmKeyMap *keymap;
bool is_modal_event;
} ViewOpsData;
/* view3d_navigate.cc */

View File

@@ -489,6 +489,8 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(struct bContext *C,
struct ListBase *handlers,
const struct wmEvent *event);
bool WM_event_match(const struct wmEvent *winevent, const struct wmKeyMapItem *kmi);
typedef int (*wmUIHandlerFunc)(struct bContext *C, const struct wmEvent *event, void *userdata);
typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata);

View File

@@ -2205,7 +2205,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
}
}
static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
BLI_INLINE bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
{
if (kmi->flag & KMI_INACTIVE) {
return false;
@@ -6019,6 +6019,11 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
return nullptr;
}
bool WM_event_match(const wmEvent *winevent, const wmKeyMapItem *kmi)
{
return wm_eventmatch(winevent, kmi);
}
/** \} */
/* -------------------------------------------------------------------- */