Allow navigating while transforming

This feature has been desired for some time:
- https://rightclickselect.com/p/ui/Tqbbbc/allow-navigating-while-transforming (See comments);
- D1583;
- T37427;

In short, blocking navigation during transform limits the user to move the object only to visible areas within the screen and hinders the allocation of objects within closed meshes.

The node editor is also impaired because some nodes are far between them and the connectors are too small.

The only disadvantage of this patch (as I see it) is the conflict with the existing key map:
MIDDLEMOUSE:
- enable axis constrain in 3D view;

WHEELDOWNMOUSE, WHEELUPMOUSE, PAGEUPKEY, PAGEDOWNKEY:
- change the threshold of the proportional edit;

So the patch solution was to change these keymaps:
- MIDDLEMOUSE to Alt+MIDDLEMOUSE;
- WHEELDOWNMOUSE, WHEELUPMOUSE, PAGEUPKEY, PAGEDOWNKEY to Alt+(corresponding key);

When you use this new keymap for the first time in the proportional edit, it may seem strange due to the custom of using it (both in View2D and View3D).
But quickly the user gets used to it.

Alternatively we can add an option to the user preferences ([] Allow navigating while transforming). (I'm not much fan of this option).

The patch was done on branch2.8. But maybe it's a good idea to apply it to 2.79

Differential Revision: https://developer.blender.org/D2624
This commit is contained in:
Germano Cavalcante 2021-11-16 21:05:30 -03:00 committed by Germano Cavalcante
parent cb3ba68ec4
commit 1d1855e95f
Notes: blender-bot 2023-02-14 06:00:44 +01:00
Referenced by commit 5e6fdaa07f, Revert "Allow navigating while transforming"
13 changed files with 548 additions and 29 deletions

View File

@ -2292,8 +2292,16 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
({"property": "use_sculpt_tools_tilt"}, "T82877"),
({"property": "use_extended_asset_browser"}, ("project/view/130/", "Project Page")),
({"property": "use_override_templates"}, ("T73318", "Milestone 4")),
({"property": "use_navigate_while_transform"}, ("T73993", "Milestone 2")),
),
)
experimental = context.preferences.experimental
if experimental.use_navigate_while_transform:
split = self.layout.split(factor=0.66)
row = split.split()
row.operator("transform.modalkeymap_update")
row.operator("transform.modalkeymap_restore")
class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):

View File

@ -108,9 +108,6 @@ void setTransformViewMatrices(TransInfo *t)
unit_m4(t->persinv);
t->persp = RV3D_ORTHO;
}
calculateCenter2D(t);
calculateCenterLocal(t, t->center_global);
}
void setTransformViewAspect(TransInfo *t, float r_aspect[3])
@ -902,8 +899,6 @@ int transformEvent(TransInfo *t, const wmEvent *event)
t->con.mode |= CON_SELECT;
}
copy_v2_v2_int(t->mval, event->mval);
/* Use this for soft redraw. Might cause flicker in object mode */
// t->redraw |= TREDRAW_SOFT;
t->redraw |= TREDRAW_HARD;

View File

@ -155,6 +155,9 @@ typedef enum {
/** No cursor wrapping on region bounds */
T_NO_CURSOR_WRAP = 1 << 23,
/** To indicate that V3D matrices have changed due to navigation. */
T_VIEW_DIRTY = 1 << 24,
} eTFlag;
/** #TransInfo.modifiers */
@ -766,6 +769,7 @@ void applyMouseInput(struct TransInfo *t,
const int mval[2],
float output[3]);
void transform_input_reset(MouseInput *mi, const int mval[2]);
void transform_input_update(TransInfo *t, const float fac);
void setCustomPoints(TransInfo *t, MouseInput *mi, const int start[2], const int end[2]);
void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2]);
@ -798,6 +802,7 @@ void calculateCenter2D(TransInfo *t);
void calculateCenterLocal(TransInfo *t, const float center_global[3]);
void calculateCenter(TransInfo *t);
void tranformViewUpdate(TransInfo *t);
/* API functions for getting center points */
void calculateCenterBound(TransInfo *t, float r_center[3]);

View File

@ -164,6 +164,7 @@ void createTransNodeData(TransInfo *t)
void flushTransNodes(TransInfo *t)
{
const float dpi_fac = UI_DPI_FAC;
float offset[2] = {0.0f, 0.0f};
View2DEdgePanData *customdata = (View2DEdgePanData *)t->custom.type.data;
@ -177,14 +178,16 @@ void flushTransNodes(TransInfo *t)
t->region->winrct.xmin + t->mval[0],
t->region->winrct.ymin + t->mval[1],
};
const rctf rect = t->region->v2d.cur;
UI_view2d_edge_pan_apply(t->context, customdata, xy);
if (!BLI_rctf_compare(&rect, &t->region->v2d.cur, FLT_EPSILON)) {
/* Additional offset due to change in view2D rect. */
BLI_rctf_transform_pt_v(&t->region->v2d.cur, &rect, offset, offset);
t->flag |= T_VIEW_DIRTY;
}
}
}
/* Initial and current view2D rects for additional transform due to view panning and zooming */
const rctf *rect_src = &customdata->initial_rect;
const rctf *rect_dst = &t->region->v2d.cur;
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
applyGridAbsolute(t);
@ -195,10 +198,7 @@ void flushTransNodes(TransInfo *t)
bNode *node = td->extra;
float loc[2];
copy_v2_v2(loc, td2d->loc);
/* additional offset due to change in view2D rect */
BLI_rctf_transform_pt_v(rect_dst, rect_src, loc, loc);
add_v2_v2v2(loc, td2d->loc, offset);
#ifdef USE_NODE_CENTER
loc[0] -= 0.5f * BLI_rctf_size_x(&node->totr);

View File

@ -679,6 +679,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
setTransformViewMatrices(t);
calculateCenter2D(t);
calculateCenterLocal(t, t->center_global);
initNumInput(&t->num);
}
@ -1140,6 +1142,33 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[
}
}
static void calculateZfac(TransInfo *t)
{
/* ED_view3d_calc_zfac() defines a factor for perspective depth correction,
* used in ED_view3d_win_to_delta() */
/* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW
* and never used in other cases.
*
* We need special case here as well, since ED_view3d_calc_zfac will crash when called
* for a region different from RGN_TYPE_WINDOW.
*/
if (t->spacetype == SPACE_VIEW3D) {
t->zfac = ED_view3d_calc_zfac(t->region->regiondata, t->center_global, NULL);
}
else if (t->spacetype == SPACE_IMAGE) {
SpaceImage *sima = t->area->spacedata.first;
t->zfac = 1.0f / sima->zoom;
}
else {
View2D *v2d = &t->region->v2d;
/* Get zoom fac the same way as in
* `ui_view2d_curRect_validate_resize` - better keep in sync! */
const float zoomx = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur);
t->zfac = 1.0f / zoomx;
}
}
void calculateCenter(TransInfo *t)
{
if ((t->flag & T_OVERRIDE_CENTER) == 0) {
@ -1174,23 +1203,38 @@ void calculateCenter(TransInfo *t)
}
}
if (t->spacetype == SPACE_VIEW3D) {
/* ED_view3d_calc_zfac() defines a factor for perspective depth correction,
* used in ED_view3d_win_to_delta() */
calculateZfac(t);
}
/* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW
* and never used in other cases.
*
* We need special case here as well, since ED_view3d_calc_zfac will crash when called
* for a region different from RGN_TYPE_WINDOW.
*/
if (t->region->regiontype == RGN_TYPE_WINDOW) {
t->zfac = ED_view3d_calc_zfac(t->region->regiondata, t->center_global, NULL);
}
else {
t->zfac = 0.0f;
/* Called every time the view changes due to navigation.
* Adjusts the mouse position relative to the object. */
void tranformViewUpdate(TransInfo *t)
{
if (t->spacetype == SPACE_VIEW3D) {
setTransformViewMatrices(t);
for (int i = 0; i < ARRAY_SIZE(t->orient); i++) {
if (t->orient[i].type == V3D_ORIENT_VIEW) {
copy_m3_m4(t->orient[i].matrix, t->viewinv);
normalize_m3(t->orient[i].matrix);
if (t->orient_curr == i) {
copy_m3_m3(t->spacemtx, t->orient[i].matrix);
invert_m3_m3_safe_ortho(t->spacemtx_inv, t->spacemtx);
}
}
}
}
float fac = 1.0f;
if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) {
float zfac_prev = t->zfac;
calculateZfac(t);
fac = zfac_prev / t->zfac;
}
calculateCenter2D(t);
transform_input_update(t, fac);
t->flag &= ~T_VIEW_DIRTY;
}
void calculatePropRatio(TransInfo *t)

View File

@ -459,6 +459,32 @@ void applyMouseInput(TransInfo *t, MouseInput *mi, const int mval[2], float outp
}
}
void transform_input_update(TransInfo *t, const float fac)
{
MouseInput *mi = &t->mouse;
int offset[2], center_2d_int[2] = {mi->center[0], mi->center[1]};
sub_v2_v2v2_int(offset, mi->imval, center_2d_int);
offset[0] *= fac;
offset[1] *= fac;
t->mouse.factor *= fac;
center_2d_int[0] = t->center2d[0];
center_2d_int[1] = t->center2d[1];
add_v2_v2v2_int(mi->imval, center_2d_int, offset);
float center_old[2];
copy_v2_v2(center_old, mi->center);
copy_v2_v2(mi->center, t->center2d);
if (ELEM(mi->apply, InputAngle, InputAngleSpring)) {
float offset_center[2];
sub_v2_v2v2(offset_center, mi->center, center_old);
struct InputAngle_Data *data = mi->data;
data->mval_prev[0] += offset_center[0];
data->mval_prev[1] += offset_center[1];
}
}
void transform_input_reset(MouseInput *mi, const int mval[2])
{
copy_v2_v2_int(mi->imval, mval);

View File

@ -23,7 +23,10 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_alloca.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@ -421,7 +424,17 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
#endif
if (event->type == MOUSEMOVE) {
copy_v2_v2_int(t->mval, event->mval);
}
if (WM_operator_do_navigation(C, op, event)) {
t->flag |= T_VIEW_DIRTY;
return OPERATOR_RUNNING_MODAL;
}
else if (t->flag & T_VIEW_DIRTY) {
tranformViewUpdate(t);
}
/* XXX insert keys are called here, and require context */
t->context = C;
exit_code = transformEvent(t, event);
@ -1352,6 +1365,321 @@ static void TRANSFORM_OT_from_gizmo(struct wmOperatorType *ot)
ot->invoke = transform_from_gizmo_invoke;
}
static wmKeyMapItem **navigation_keymaps(bContext *C, int *r_kmi_len)
{
wmKeyMapItem *km_items[70];
int kmi_len = 0;
const char *op_names[] = {
/* 3D View. */
"VIEW3D_OT_zoom",
"VIEW3D_OT_rotate",
"VIEW3D_OT_move",
"VIEW3D_OT_view_pan",
"VIEW3D_OT_dolly",
"VIEW3D_OT_view_orbit",
"VIEW3D_OT_view_roll",
#ifdef WITH_INPUT_NDOF
"VIEW3D_OT_ndof_orbit_zoom",
"VIEW3D_OT_ndof_orbit",
"VIEW3D_OT_ndof_pan",
"VIEW3D_OT_ndof_all",
#endif
/* Image. */
"IMAGE_OT_view_pan",
"IMAGE_OT_view_zoom_in",
"IMAGE_OT_view_zoom_out",
#ifdef WITH_INPUT_NDOF
"IMAGE_OT_view_ndof",
#endif
/* View2D. */
"VIEW2D_OT_pan",
"VIEW2D_OT_zoom_in",
"VIEW2D_OT_zoom_out",
#ifdef WITH_INPUT_NDOF
"VIEW2D_OT_ndof",
#endif
};
wmWindowManager *wm = CTX_wm_manager(C);
wmKeyMap *keymap[3];
keymap[0] = WM_keymap_find_all(wm, "3D View", SPACE_VIEW3D, 0);
keymap[1] = WM_keymap_find_all(wm, "Image", SPACE_IMAGE, 0);
keymap[2] = WM_keymap_find_all(wm, "View2D", 0, 0);
for (int i = 0; i < 3; i++) {
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap[i]->items) {
if (!(STRPREFIX(kmi->idname, "VIEW") || STRPREFIX(kmi->idname, "IMAGE"))) {
continue;
}
if (kmi->flag & KMI_INACTIVE) {
continue;
}
for (int i = 0; i < ARRAY_SIZE(op_names); i++) {
if (STREQ(kmi->idname, op_names[i])) {
km_items[kmi_len++] = kmi;
break;
}
}
if (kmi_len == ARRAY_SIZE(km_items)) {
BLI_assert(false);
break;
}
}
}
size_t km_items_size = sizeof(void *) * kmi_len;
wmKeyMapItem **r_km_items = MEM_mallocN(km_items_size, __func__);
memcpy(r_km_items, km_items, km_items_size);
*r_kmi_len = kmi_len;
return r_km_items;
}
static bool kmi_cmp(const wmKeyMapItem *kmi_a, const wmKeyMapItem *kmi_b)
{
if (kmi_a->shift != kmi_b->shift) {
return false;
}
if (kmi_a->ctrl != kmi_b->ctrl) {
return false;
}
if (kmi_a->alt != kmi_b->alt) {
return false;
}
if (kmi_a->oskey != kmi_b->oskey) {
return false;
}
if (!ELEM(kmi_b->type, kmi_a->type, KM_ANY)) {
bool is_wheelin_modal = ELEM(kmi_b->type, WHEELUPMOUSE, WHEELINMOUSE);
bool is_wheelout_modal = ELEM(kmi_b->type, WHEELDOWNMOUSE, WHEELOUTMOUSE);
bool is_wheelin = ELEM(kmi_a->type, WHEELUPMOUSE, WHEELINMOUSE);
bool is_wheelout = ELEM(kmi_a->type, WHEELDOWNMOUSE, WHEELOUTMOUSE);
if (!(is_wheelin_modal || is_wheelout_modal) ||
((is_wheelin_modal != is_wheelin) || (is_wheelout_modal != is_wheelout))) {
return false;
}
}
if (!ELEM(kmi_b->val, kmi_a->val, KM_ANY)) {
return false;
}
if (kmi_a->keymodifier != kmi_b->keymodifier) {
return false;
}
return true;
}
static const wmKeyMapItem *modalmap_is_conflicting(wmKeyMapItem **km_items,
const int km_items_len,
wmKeyMapItem *kmi_modal)
{
for (int i = 0; i < km_items_len; i++) {
const wmKeyMapItem *kmi = km_items[i];
if (kmi_cmp(kmi, kmi_modal)) {
return kmi;
}
}
return NULL;
}
#define LABEL_LINE_SIZE 140
struct KMConflict {
wmKeyMapItem *kmi;
wmKeyMapItem kmi_new;
char descr[LABEL_LINE_SIZE];
};
struct KMConflictOPData {
int conflicts_len;
struct KMConflict conflicts[0];
};
static void modalkeymap_conflict_free(wmOperator *op)
{
struct KMConflictOPData *data = op->customdata;
MEM_freeN(data);
}
static int modalkeymap_update_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
int kmi_navigate_len;
wmKeyMapItem **kmi_navigate = navigation_keymaps(C, &kmi_navigate_len);
struct KMConflict conflicts[10];
int conflicts_len = 0;
wmWindowManager *wm = CTX_wm_manager(C);
wmKeyConfig *keyconf = wm->userconf;
wmKeyMap *modalmap = WM_keymap_active(wm, WM_modalkeymap_find(keyconf, "Transform Modal Map"));
LISTBASE_FOREACH (wmKeyMapItem *, kmi_modal, &modalmap->items) {
if (kmi_modal->flag & KMI_INACTIVE) {
continue;
}
const wmKeyMapItem *kmi = modalmap_is_conflicting(kmi_navigate, kmi_navigate_len, kmi_modal);
if (kmi) {
struct KMConflict *conflict = &conflicts[conflicts_len++];
conflict->kmi = kmi_modal;
conflict->kmi_new = *kmi_modal;
conflict->kmi_new.alt = true;
wmKeyMapItem *kmi_new = &conflict->kmi_new;
const char *name;
char descriptor[LABEL_LINE_SIZE], descriptor_new[LABEL_LINE_SIZE];
WM_keymap_item_to_string(kmi_modal, false, descriptor, LABEL_LINE_SIZE);
WM_keymap_item_to_string(kmi_new, false, descriptor_new, LABEL_LINE_SIZE);
RNA_enum_name(modalmap->modal_items, kmi_modal->propvalue, &name);
BLI_snprintf(conflict->descr,
LABEL_LINE_SIZE,
"\"%s\" will change from '%s' to '%s' (as it conflicts with \"%s\")",
TIP_(name),
descriptor,
descriptor_new,
kmi->idname);
}
}
MEM_freeN(kmi_navigate);
if (!conflicts_len) {
return OPERATOR_CANCELLED;
}
struct KMConflictOPData *data;
size_t conflicts_size = sizeof(struct KMConflict) * conflicts_len;
data = MEM_mallocN(sizeof(struct KMConflictOPData) + conflicts_size, __func__);
data->conflicts_len = conflicts_len;
memcpy(data->conflicts, conflicts, conflicts_size);
op->customdata = data;
return WM_operator_props_dialog_popup(C, op, 750);
}
static int modalkeymap_exec(bContext *UNUSED(C), wmOperator *op)
{
struct KMConflictOPData *data = op->customdata;
struct KMConflict *conflicts = data->conflicts;
for (int i = 0; i < data->conflicts_len; i++) {
struct KMConflict *conflict = &conflicts[i];
*conflict->kmi = conflict->kmi_new;
WM_keyconfig_update_tag(NULL, conflict->kmi);
}
modalkeymap_conflict_free(op);
if (U.runtime.is_dirty == false) {
U.runtime.is_dirty = true;
WM_main_add_notifier(NC_WINDOW, NULL);
}
return OPERATOR_FINISHED;
}
static void modalkeymap_cancel(bContext *UNUSED(C), wmOperator *op)
{
modalkeymap_conflict_free(op);
}
static void modalkeymap_draw(bContext *UNUSED(C), wmOperator *op)
{
struct KMConflictOPData *data = op->customdata;
struct KMConflict *conflicts = data->conflicts;
for (int i = 0; i < data->conflicts_len; i++) {
struct KMConflict *conflict = &conflicts[i];
uiItemL(op->layout, conflict->descr, ICON_DOT);
}
}
static void TRANSFORM_OT_modalkeymap_update(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Update Transform Modal Map";
ot->description = "Edit the Transform Modal Map to avoid conflicts with navigation shortcuts";
ot->idname = "TRANSFORM_OT_modalkeymap_update";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* api callbacks */
ot->invoke = modalkeymap_update_invoke;
ot->exec = modalkeymap_exec;
ot->cancel = modalkeymap_cancel;
ot->ui = modalkeymap_draw;
}
static int modalkeymap_restore_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
struct KMConflict conflicts[10];
int conflicts_len = 0;
wmWindowManager *wm = CTX_wm_manager(C);
wmKeyMap *modalmap = WM_modalkeymap_find(wm->defaultconf, "Transform Modal Map");
wmKeyMap *modalmap_act = WM_keymap_active(
wm, WM_modalkeymap_find(wm->userconf, "Transform Modal Map"));
wmKeyMapItem *kmi_orig = modalmap->items.first, *kmi = modalmap_act->items.first;
while (kmi_orig && kmi) {
if (!kmi_cmp(kmi_orig, kmi)) {
struct KMConflict *conflict = &conflicts[conflicts_len++];
conflict->kmi = kmi;
conflict->kmi_new = *kmi_orig;
wmKeyMapItem *kmi_new = &conflict->kmi_new;
const char *name;
char descriptor[LABEL_LINE_SIZE], descriptor_new[LABEL_LINE_SIZE];
WM_keymap_item_to_string(kmi, false, descriptor, LABEL_LINE_SIZE);
WM_keymap_item_to_string(kmi_new, false, descriptor_new, LABEL_LINE_SIZE);
RNA_enum_name(modalmap->modal_items, kmi->propvalue, &name);
BLI_snprintf(conflict->descr,
LABEL_LINE_SIZE,
"\"%s\" will be restored from '%s' to '%s'",
TIP_(name),
descriptor,
descriptor_new);
}
kmi_orig = kmi_orig->next;
kmi = kmi->next;
}
if (!conflicts_len) {
return OPERATOR_CANCELLED;
}
struct KMConflictOPData *data;
size_t conflicts_size = sizeof(struct KMConflict) * conflicts_len;
data = MEM_mallocN(sizeof(struct KMConflictOPData) + conflicts_size, __func__);
data->conflicts_len = conflicts_len;
memcpy(data->conflicts, conflicts, conflicts_size);
op->customdata = data;
return WM_operator_props_dialog_popup(C, op, 600);
}
static int modalkeymap_restore_exec(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmKeyConfig *keyconf = wm->userconf;
wmKeyMap *modalmap = WM_modalkeymap_find(keyconf, "Transform Modal Map");
WM_keymap_restore_to_default(modalmap, wm);
modalkeymap_conflict_free(op);
if (U.runtime.is_dirty == false) {
U.runtime.is_dirty = true;
WM_main_add_notifier(NC_WINDOW, NULL);
}
return OPERATOR_FINISHED;
}
static void TRANSFORM_OT_modalkeymap_restore(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Restore Transform Modal Map";
ot->description = "Restore Transform Modal Map to Default";
ot->idname = "TRANSFORM_OT_modalkeymap_restore";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* api callbacks */
ot->invoke = modalkeymap_restore_invoke;
ot->exec = modalkeymap_restore_exec;
ot->cancel = modalkeymap_cancel;
ot->ui = modalkeymap_draw;
}
void transform_operatortypes(void)
{
TransformModeItem *tmode;
@ -1367,6 +1695,9 @@ void transform_operatortypes(void)
WM_operatortype_append(TRANSFORM_OT_delete_orientation);
WM_operatortype_append(TRANSFORM_OT_from_gizmo);
WM_operatortype_append(TRANSFORM_OT_modalkeymap_update);
WM_operatortype_append(TRANSFORM_OT_modalkeymap_restore);
}
void ED_keymap_transform(wmKeyConfig *keyconf)

View File

@ -663,7 +663,8 @@ typedef struct UserDef_Experimental {
char use_sculpt_tools_tilt;
char use_extended_asset_browser;
char use_override_templates;
char _pad[2];
char use_navigate_while_transform;
char _pad;
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;

View File

@ -6414,6 +6414,10 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "use_geometry_nodes_legacy", 1);
RNA_def_property_ui_text(
prop, "Geometry Nodes Legacy", "Enable legacy geometry nodes in the menu");
prop = RNA_def_property(srna, "use_navigate_while_transform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
prop, "Navigate While Transform", "Allow Navigation While Transforming");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)

View File

@ -640,6 +640,9 @@ char *WM_operatortype_description_or_name(struct bContext *C,
/* wm_operator_utils.c */
void WM_operator_type_modal_from_exec_for_object_edit_coords(struct wmOperatorType *ot);
bool WM_operator_do_navigation(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
/* wm_uilist_type.c */
void WM_uilisttype_init(void);

View File

@ -2003,7 +2003,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
}
}
static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
{
if (kmi->flag & KMI_INACTIVE) {
return false;

View File

@ -21,7 +21,9 @@
*/
#include <math.h>
#include <string.h>
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@ -35,6 +37,8 @@
#include "WM_api.h" /* Own include. */
#include "WM_types.h"
#include "wm_event_system.h"
#include "MEM_guardedalloc.h"
#include "ED_object.h"
@ -358,4 +362,101 @@ void WM_operator_type_modal_from_exec_for_object_edit_coords(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
bool WM_operator_do_navigation(bContext *C, wmOperator *op, const wmEvent *event)
{
const char *op_names[] = {
/* 3D View. */
"VIEW3D_OT_zoom",
"VIEW3D_OT_rotate",
"VIEW3D_OT_move",
"VIEW3D_OT_view_pan",
"VIEW3D_OT_dolly",
"VIEW3D_OT_view_orbit",
"VIEW3D_OT_view_roll",
#ifdef WITH_INPUT_NDOF
"VIEW3D_OT_ndof_orbit_zoom",
"VIEW3D_OT_ndof_orbit",
"VIEW3D_OT_ndof_pan",
"VIEW3D_OT_ndof_all",
#endif
/* Image. */
"IMAGE_OT_view_pan",
"IMAGE_OT_view_zoom_in",
"IMAGE_OT_view_zoom_out",
#ifdef WITH_INPUT_NDOF
"IMAGE_OT_view_ndof",
#endif
/* View2D. */
"VIEW2D_OT_pan",
"VIEW2D_OT_zoom_in",
"VIEW2D_OT_zoom_out",
#ifdef WITH_INPUT_NDOF
"VIEW2D_OT_ndof",
#endif
};
static struct {
wmKeyMapItem *kmi;
wmOperatorType *ot;
} kmi_ot[70];
static int kmi_ot_len;
/* Lazy initialization (avoids having to allocating a context). */
static wmOperatorType *ot_last = NULL;
static char spacetype_last = SPACE_EMPTY;
SpaceLink *sl = CTX_wm_space_data(C);
if ((ot_last != op->type) || (spacetype_last != sl->spacetype)) {
ot_last = op->type;
spacetype_last = sl->spacetype;
wmWindowManager *wm = CTX_wm_manager(C);
wmKeyMap *km;
if (sl->spacetype == SPACE_VIEW3D) {
km = WM_keymap_find_all(wm, "3D View", SPACE_VIEW3D, 0);
}
else if (sl->spacetype == SPACE_IMAGE) {
km = WM_keymap_find_all(wm, "Image", SPACE_IMAGE, 0);
}
else {
km = WM_keymap_find_all(wm, "View2D", 0, 0);
}
kmi_ot_len = 0;
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
if (!(STRPREFIX(kmi->idname, "VIEW") || STRPREFIX(kmi->idname, "IMAGE"))) {
continue;
}
if (kmi->flag & KMI_INACTIVE) {
continue;
}
for (int i = 0; i < ARRAY_SIZE(op_names); i++) {
if (STREQ(kmi->idname, op_names[i])) {
kmi_ot[kmi_ot_len].kmi = kmi;
kmi_ot[kmi_ot_len].ot = WM_operatortype_find(op_names[i], true);
kmi_ot_len++;
break;
}
}
if (kmi_ot_len == ARRAY_SIZE(kmi_ot)) {
BLI_assert(false);
break;
}
}
}
if (event->type == EVT_MODAL_MAP) {
wmWindow *win = CTX_wm_window(C);
event = win->eventstate;
}
for (int i = 0; i < kmi_ot_len; i++) {
if (wm_eventmatch(event, kmi_ot[i].kmi)) {
return WM_operator_name_call_ptr(
C, kmi_ot[i].ot, WM_OP_INVOKE_DEFAULT, kmi_ot[i].kmi->ptr) != OPERATOR_CANCELLED;
}
}
return false;
}
/** \} */

View File

@ -147,6 +147,7 @@ typedef struct wmEventHandler_Dropbox {
void wm_event_free_all(wmWindow *win);
void wm_event_free(wmEvent *event);
void wm_event_free_handler(wmEventHandler *handler);
bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi);
/* goes over entire hierarchy: events -> window -> screen -> area -> region */
void wm_event_do_handlers(bContext *C);