diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2020-02-04 22:06:36 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2020-02-04 22:09:03 +0300 |
commit | e4605cb155bc26171f4f1bd62a2bbfcce482fb0c (patch) | |
tree | b5d7d666f8b84466f07f748e4477fa9fad1dfac6 | |
parent | fd130a711e99723924e99a60a9e11162ca278fd8 (diff) | |
parent | f7ca86369da89a6726bc9edc9bf4e875b2b43c46 (diff) |
Merge branch 'blender-v2.82-release'
-rw-r--r-- | build_files/cmake/clang_array_check.py | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/report.c | 5 | ||||
-rw-r--r-- | source/blender/draw/engines/overlay/overlay_armature.c | 9 | ||||
-rw-r--r-- | source/blender/draw/engines/overlay/overlay_private.h | 1 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_curve.c | 3 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_hair.c | 28 | ||||
-rw-r--r-- | source/blender/draw/intern/shaders/common_hair_lib.glsl | 9 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 1 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 559 |
9 files changed, 503 insertions, 114 deletions
diff --git a/build_files/cmake/clang_array_check.py b/build_files/cmake/clang_array_check.py index f55b0950383..de0b55c70e0 100644 --- a/build_files/cmake/clang_array_check.py +++ b/build_files/cmake/clang_array_check.py @@ -33,7 +33,7 @@ defs_precalc = { "glColor3ubv": {0: 3}, "glColor4ubv": {0: 4}, - "glColor4usv": {0: 3}, + "glColor3usv": {0: 3}, "glColor4usv": {0: 4}, "glColor3fv": {0: 3}, diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c index 5db091e6a43..6b8d7f856ce 100644 --- a/source/blender/blenkernel/intern/report.c +++ b/source/blender/blenkernel/intern/report.c @@ -76,6 +76,11 @@ void BKE_reports_init(ReportList *reports, int flag) reports->flag = flag; } +/** + * Only frees the list \a reports. + * To make displayed reports disappear, either remove window-manager reports + * (wmWindowManager.reports, or CTX_wm_reports()), or use #WM_report_banners_cancel(). + */ void BKE_reports_clear(ReportList *reports) { Report *report, *report_next; diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index c31e63b2550..4571446763c 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -153,7 +153,8 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) XRAY_FLAG_ENABLED(draw_ctx->v3d); pd->armature.show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0) && !is_select_mode; - pd->armature.do_pose_fade_geom = (pd->overlay.flag & V3D_OVERLAY_BONE_SELECT) && + pd->armature.do_pose_xray = (pd->overlay.flag & V3D_OVERLAY_BONE_SELECT) != 0; + pd->armature.do_pose_fade_geom = pd->armature.do_pose_xray && ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) && draw_ctx->object_pose != NULL; @@ -2238,8 +2239,7 @@ static void armature_context_setup(ArmatureDrawContext *ctx, float *const_color) { const bool is_object_mode = !do_envelope_dist; - const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0 || - (pd->armature.do_pose_fade_geom && is_pose_mode); + const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0 || (pd->armature.do_pose_xray && is_pose_mode); const bool draw_as_wire = (ob->dt < OB_SOLID); const bool is_filled = (!pd->armature.transparent && !draw_as_wire) || !is_object_mode; const bool is_transparent = pd->armature.transparent || (draw_as_wire && !is_object_mode); @@ -2424,7 +2424,8 @@ void OVERLAY_pose_draw(OVERLAY_Data *vedata) DRW_draw_pass(psl->armature_bone_select_ps); if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_line_fb); + GPU_framebuffer_bind(fbl->overlay_line_in_front_fb); + GPU_framebuffer_clear_depth(fbl->overlay_line_in_front_fb, 1.0f); } DRW_draw_pass(psl->armature_ps[1]); diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index afec20b477d..f8eeeed42ef 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -300,6 +300,7 @@ typedef struct OVERLAY_PrivateData { struct { bool transparent; bool show_relations; + bool do_pose_xray; bool do_pose_fade_geom; } armature; struct { diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index 85340fae35d..25699cd7653 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -949,8 +949,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob) /* Init batches and request VBOs & IBOs */ if (DRW_batch_requested(cache->batch.surfaces, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.surfaces, &cache->ibo.surfaces_tris); - DRW_vbo_request(cache->batch.surfaces, &cache->ordered.pos_nor); + DRW_vbo_request(cache->batch.surfaces, &cache->ordered.loop_pos_nor); } if (DRW_batch_requested(cache->batch.surfaces_edges, GPU_PRIM_LINES)) { DRW_ibo_request(cache->batch.surfaces_edges, &cache->ibo.surfaces_lines); diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 58085cf08c6..08256b931ba 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -104,12 +104,6 @@ void DRW_hair_init(void) #endif } -typedef struct DRWHairInstanceData { - DrawData dd; - - float mat[4][4]; -} DRWHairInstanceData; - static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, ParticleSystem *psys, ModifierData *md, @@ -120,13 +114,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, /* TODO(fclem): Pass the scene as parameter */ const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - static float unit_mat[4][4] = { - {1, 0, 0, 0}, - {0, 1, 0, 0}, - {0, 0, 1, 0}, - {0, 0, 0, 1}, - }; - float(*dupli_mat)[4]; + float dupli_mat[4][4]; Object *dupli_parent = DRW_object_get_dupli_parent(object); DupliObject *dupli_object = DRW_object_get_dupli(object); @@ -164,13 +152,6 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, } if ((dupli_parent != NULL) && (dupli_object != NULL)) { - DRWHairInstanceData *hair_inst_data = (DRWHairInstanceData *)DRW_drawdata_ensure( - &object->id, - (DrawEngineType *)&drw_shgroup_create_hair_procedural_ex, - sizeof(DRWHairInstanceData), - NULL, - NULL); - dupli_mat = hair_inst_data->mat; if (dupli_object->type & OB_DUPLICOLLECTION) { copy_m4_m4(dupli_mat, dupli_parent->obmat); } @@ -181,14 +162,17 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, } } else { - dupli_mat = unit_mat; + unit_m4(dupli_mat); } DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_tex); DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1); DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res); DRW_shgroup_uniform_float(shgrp, "hairRadShape", &part->shape, 1); - DRW_shgroup_uniform_mat4(shgrp, "hairDupliMatrix", dupli_mat); + DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[0]", dupli_mat[0]); + DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[1]", dupli_mat[1]); + DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[2]", dupli_mat[2]); + DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[3]", dupli_mat[3]); DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", part->rad_root * part->rad_scale * 0.5f); DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", part->rad_tip * part->rad_scale * 0.5f); DRW_shgroup_uniform_bool_copy( diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl index cbcdc947bc7..ffff631e34b 100644 --- a/source/blender/draw/intern/shaders/common_hair_lib.glsl +++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl @@ -26,7 +26,7 @@ uniform float hairRadTip = 0.0; uniform float hairRadShape = 0.5; uniform bool hairCloseTip = true; -uniform mat4 hairDupliMatrix; +uniform vec4 hairDupliMatrix[4]; /* -- Per control points -- */ uniform samplerBuffer hairPointBuffer; /* RGBA32F */ @@ -159,8 +159,11 @@ void hair_get_pos_tan_binor_time(bool is_persp, wtan = wpos - texelFetch(hairPointBuffer, id - 1).point_position; } - wpos = (hairDupliMatrix * vec4(wpos, 1.0)).xyz; - wtan = -normalize(mat3(hairDupliMatrix) * wtan); + mat4 obmat = mat4( + hairDupliMatrix[0], hairDupliMatrix[1], hairDupliMatrix[2], hairDupliMatrix[3]); + + wpos = (obmat * vec4(wpos, 1.0)).xyz; + wtan = -normalize(mat3(obmat) * wtan); vec3 camera_vec = (is_persp) ? camera_pos - wpos : camera_z; wbinor = normalize(cross(camera_vec, wtan)); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index cfdb15026fd..f5cf0b7d0c2 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -307,6 +307,7 @@ void WM_main_remap_editor_id_reference(struct ID *old_id, struct ID *new_id); /* reports */ void WM_report_banner_show(void); +void WM_report_banners_cancel(struct Main *bmain); void WM_report(ReportType type, const char *message); void WM_reportf(ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 7339f463855..ebcdef47eee 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -70,6 +70,7 @@ #include "RNA_access.h" #include "UI_interface.h" +#include "UI_view2d.h" #include "PIL_time.h" @@ -83,6 +84,8 @@ #include "wm_event_system.h" #include "wm_event_types.h" +#include "RNA_enum_types.h" + #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -101,6 +104,7 @@ #define USE_GIZMO_MOUSE_PRIORITY_HACK static void wm_notifier_clear(wmNotifier *note); +static void update_tablet_data(wmWindow *win, wmEvent *event); static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, @@ -110,8 +114,6 @@ static int wm_operator_call_internal(bContext *C, const bool poll_only, wmEvent *event); -static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot); - /* -------------------------------------------------------------------- */ /** \name Event Management * \{ */ @@ -124,6 +126,14 @@ wmEvent *wm_event_add_ex(wmWindow *win, *event = *event_to_add; + update_tablet_data(win, event); + + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + /* We could have a preference to support relative tablet motion (we can't detect that). */ + event->is_motion_absolute = ((event->tablet_data != NULL) && + (event->tablet_data->Active != GHOST_kTabletModeNone)); + } + if (event_to_add_after == NULL) { BLI_addtail(&win->queue, event); } @@ -167,6 +177,10 @@ void wm_event_free(wmEvent *event) } } + if (event->tablet_data) { + MEM_freeN((void *)event->tablet_data); + } + MEM_freeN(event); } @@ -181,6 +195,9 @@ void wm_event_free_all(wmWindow *win) void wm_event_init_from_window(wmWindow *win, wmEvent *event) { + /* make sure we don't copy any owned pointers */ + BLI_assert(win->eventstate->tablet_data == NULL); + *event = *(win->eventstate); } @@ -689,6 +706,26 @@ void WM_report_banner_show(void) wm_reports->reporttimer->customdata = rti; } +/** + * Hide all currently displayed banners and abort their timer. + */ +void WM_report_banners_cancel(Main *bmain) +{ + wmWindowManager *wm = bmain->wm.first; + BKE_reports_clear(&wm->reports); + WM_event_remove_timer(wm, NULL, wm->reports.reporttimer); +} + +bool WM_event_is_last_mousemove(const wmEvent *event) +{ + while ((event = event->next)) { + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + return false; + } + } + return true; +} + #ifdef WITH_INPUT_NDOF void WM_ndof_deadzone_set(float deadzone) { @@ -1202,6 +1239,105 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event) } } +#if 1 /* may want to disable operator remembering previous state for testing */ + +static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_properties) +{ + bool changed = false; + IDPropertyTemplate val = {0}; + IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties"); + PropertyRNA *iterprop; + + CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname); + + iterprop = RNA_struct_iterator_property(op->type->srna); + + RNA_PROP_BEGIN (op->ptr, itemptr, iterprop) { + PropertyRNA *prop = itemptr.data; + if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) { + if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */ + const char *identifier = RNA_property_identifier(prop); + IDProperty *idp_src = IDP_GetPropertyFromGroup(last_properties, identifier); + if (idp_src) { + IDProperty *idp_dst = IDP_CopyProperty(idp_src); + + /* note - in the future this may need to be done recursively, + * but for now RNA doesn't access nested operators */ + idp_dst->flag |= IDP_FLAG_GHOST; + + /* add to temporary group instead of immediate replace, + * because we are iterating over this group */ + IDP_AddToGroup(replaceprops, idp_dst); + changed = true; + } + } + } + } + RNA_PROP_END; + + IDP_MergeGroup(op->properties, replaceprops, true); + IDP_FreeProperty(replaceprops); + return changed; +} + +bool WM_operator_last_properties_init(wmOperator *op) +{ + bool changed = false; + if (op->type->last_properties) { + changed |= operator_last_properties_init_impl(op, op->type->last_properties); + for (wmOperator *opm = op->macro.first; opm; opm = opm->next) { + IDProperty *idp_src = IDP_GetPropertyFromGroup(op->type->last_properties, opm->idname); + if (idp_src) { + changed |= operator_last_properties_init_impl(opm, idp_src); + } + } + } + return changed; +} + +bool WM_operator_last_properties_store(wmOperator *op) +{ + if (op->type->last_properties) { + IDP_FreeProperty(op->type->last_properties); + op->type->last_properties = NULL; + } + + if (op->properties) { + CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname); + op->type->last_properties = IDP_CopyProperty(op->properties); + } + + if (op->macro.first != NULL) { + for (wmOperator *opm = op->macro.first; opm; opm = opm->next) { + if (opm->properties) { + if (op->type->last_properties == NULL) { + op->type->last_properties = IDP_New( + IDP_GROUP, &(IDPropertyTemplate){0}, "wmOperatorProperties"); + } + IDProperty *idp_macro = IDP_CopyProperty(opm->properties); + STRNCPY(idp_macro->name, opm->type->idname); + IDP_ReplaceInGroup(op->type->last_properties, idp_macro); + } + } + } + + return (op->type->last_properties != NULL); +} + +#else + +bool WM_operator_last_properties_init(wmOperator *UNUSED(op)) +{ + return false; +} + +bool WM_operator_last_properties_store(wmOperator *UNUSED(op)) +{ + return false; +} + +#endif + /** * Also used for exec when 'event' is NULL. */ @@ -1756,6 +1892,42 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) } } +/* do userdef mappings */ +int WM_userdef_event_map(int kmitype) +{ + switch (kmitype) { + case WHEELOUTMOUSE: + return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE; + case WHEELINMOUSE: + return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE; + } + + return kmitype; +} + +/** + * Use so we can check if 'wmEvent.type' is released in modal operators. + * + * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar. + */ +int WM_userdef_event_type_from_keymap_type(int kmitype) +{ + switch (kmitype) { + case EVT_TWEAK_L: + return LEFTMOUSE; + case EVT_TWEAK_M: + return MIDDLEMOUSE; + case EVT_TWEAK_R: + return RIGHTMOUSE; + case WHEELOUTMOUSE: + return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE; + case WHEELINMOUSE: + return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE; + } + + return kmitype; +} + static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi) { if (kmi->flag & KMI_INACTIVE) { @@ -1777,16 +1949,19 @@ static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi) if (kmitype != KM_ANY) { if (ELEM(kmitype, TABLET_STYLUS, TABLET_ERASER)) { - const wmTabletData *wmtab = &winevent->tablet; + const wmTabletData *wmtab = winevent->tablet_data; - if (winevent->type != LEFTMOUSE) { + if (wmtab == NULL) { + return false; + } + else if (winevent->type != LEFTMOUSE) { /* tablet events can occur on hover + keypress */ return false; } - else if ((kmitype == TABLET_STYLUS) && (wmtab->active != EVT_TABLET_STYLUS)) { + else if ((kmitype == TABLET_STYLUS) && (wmtab->Active != EVT_TABLET_STYLUS)) { return false; } - else if ((kmitype == TABLET_ERASER) && (wmtab->active != EVT_TABLET_ERASER)) { + else if ((kmitype == TABLET_ERASER) && (wmtab->Active != EVT_TABLET_ERASER)) { return false; } } @@ -1866,10 +2041,10 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap, * This is done since we only want to use double click events to match key-map items, * allowing modal functions to check for press/release events without having to interpret them. */ -static void wm_event_modalkeymap_begin(const bContext *C, - wmOperator *op, - wmEvent *event, - bool *dbl_click_disabled) +static void wm_event_modalkeymap(const bContext *C, + wmOperator *op, + wmEvent *event, + bool *dbl_click_disabled) { BLI_assert(event->type != EVT_MODAL_MAP); @@ -1922,13 +2097,25 @@ static void wm_event_modalkeymap_begin(const bContext *C, } /** - * Restore changes from #wm_event_modalkeymap_begin - * - * \warning bad hacking event system... - * better restore event type for checking of #KM_CLICK for example. - * Modal maps could use different method (ton). + * Check whether operator is allowed to run in case interface is locked, + * If interface is unlocked, will always return truth. */ -static void wm_event_modalkeymap_end(wmEvent *event, bool dbl_click_disabled) +static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot) +{ + wmWindowManager *wm = CTX_wm_manager(C); + + if (wm->is_interface_locked) { + if ((ot->flag & OPTYPE_LOCK_BYPASS) == 0) { + return false; + } + } + + return true; +} + +/* bad hacking event system... better restore event type for checking of KM_CLICK for example */ +/* XXX modal maps could use different method (ton) */ +static void wm_event_modalmap_end(wmEvent *event, bool dbl_click_disabled) { if (event->type == EVT_MODAL_MAP) { event->type = event->prevtype; @@ -1947,8 +2134,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler_base, wmEvent *event, - PointerRNA *properties, - const char *kmi_idname) + PointerRNA *properties) { int retval = OPERATOR_PASS_THROUGH; @@ -1973,7 +2159,7 @@ static int wm_handler_operator_call(bContext *C, wm_handler_op_context(C, handler, event); wm_region_mouse_co(C, event); - wm_event_modalkeymap_begin(C, op, event, &dbl_click_disabled); + wm_event_modalkeymap(C, op, event, &dbl_click_disabled); if (ot->flag & OPTYPE_UNDO) { wm->op_undo_depth++; @@ -1988,7 +2174,7 @@ static int wm_handler_operator_call(bContext *C, * the event, operator etc have all been freed. - campbell */ if (CTX_wm_manager(C) == wm) { - wm_event_modalkeymap_end(event, dbl_click_disabled); + wm_event_modalmap_end(event, dbl_click_disabled); if (ot->flag & OPTYPE_UNDO) { wm->op_undo_depth--; @@ -2050,7 +2236,7 @@ static int wm_handler_operator_call(bContext *C, } } else { - wmOperatorType *ot = WM_operatortype_find(kmi_idname, 0); + wmOperatorType *ot = WM_operatortype_find(event->keymap_idname, 0); if (ot && wm_operator_check_locked_interface(C, ot)) { bool use_last_properties = true; @@ -2388,8 +2574,10 @@ static int wm_handlers_do_keymap_with_keymap_handler( PRINT("%s: item matched '%s'\n", __func__, kmi->idname); - action |= wm_handler_operator_call( - C, handlers, &handler->head, event, kmi->ptr, kmi->idname); + /* weak, but allows interactive callback to not use rawkey */ + event->keymap_idname = kmi->idname; + + action |= wm_handler_operator_call(C, handlers, &handler->head, event, kmi->ptr); if (action & WM_HANDLER_BREAK) { /* not always_pass here, it denotes removed handler_base */ @@ -2443,11 +2631,13 @@ static int wm_handlers_do_keymap_with_gizmo_handler( if (wm_eventmatch(event, kmi)) { PRINT("%s: item matched '%s'\n", __func__, kmi->idname); + /* weak, but allows interactive callback to not use rawkey */ + event->keymap_idname = kmi->idname; + CTX_wm_gizmo_group_set(C, gzgroup); /* handler->op is called later, we want keymap op to be triggered here */ - action |= wm_handler_operator_call( - C, handlers, &handler->head, event, kmi->ptr, kmi->idname); + action |= wm_handler_operator_call(C, handlers, &handler->head, event, kmi->ptr); CTX_wm_gizmo_group_set(C, NULL); @@ -2738,7 +2928,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers } } else { - action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL, NULL); + action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL); } } else { @@ -3847,6 +4037,91 @@ void WM_event_add_mousemove(const bContext *C) window->addmousemove = 1; } +/* for modal callbacks, check configuration for how to interpret exit with tweaks */ +bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event) +{ + /* if the release-confirm userpref setting is enabled, + * tweak events can be canceled when mouse is released + */ + if (U.flag & USER_RELEASECONFIRM) { + /* option on, so can exit with km-release */ + if (event->val == KM_RELEASE) { + switch (tweak_event) { + case EVT_TWEAK_L: + case EVT_TWEAK_M: + case EVT_TWEAK_R: + return 1; + } + } + else { + /* if the initial event wasn't a tweak event then + * ignore USER_RELEASECONFIRM setting: see [#26756] */ + if (ELEM(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) { + return 1; + } + } + } + else { + /* this is fine as long as not doing km-release, otherwise + * some items (i.e. markers) being tweaked may end up getting + * dropped all over + */ + if (event->val != KM_RELEASE) { + return 1; + } + } + + return 0; +} + +bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask mask) +{ + /* Keyboard. */ + if (mask & EVT_TYPE_MASK_KEYBOARD) { + if (ISKEYBOARD(event_type)) { + return true; + } + } + else if (mask & EVT_TYPE_MASK_KEYBOARD_MODIFIER) { + if (ISKEYMODIFIER(event_type)) { + return true; + } + } + + /* Mouse. */ + if (mask & EVT_TYPE_MASK_MOUSE) { + if (ISMOUSE(event_type)) { + return true; + } + } + else if (mask & EVT_TYPE_MASK_MOUSE_WHEEL) { + if (ISMOUSE_WHEEL(event_type)) { + return true; + } + } + else if (mask & EVT_TYPE_MASK_MOUSE_GESTURE) { + if (ISMOUSE_GESTURE(event_type)) { + return true; + } + } + + /* Tweak. */ + if (mask & EVT_TYPE_MASK_TWEAK) { + if (ISTWEAK(event_type)) { + return true; + } + } + + /* Action Zone. */ + if (mask & EVT_TYPE_MASK_ACTIONZONE) { + if (IS_EVENT_ACTIONZONE(event_type)) { + return true; + } + } + + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -4084,23 +4359,41 @@ static void wm_eventemulation(wmEvent *event, bool test_only) } } -void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab) +/* applies the global tablet pressure correction curve */ +float wm_pressure_curve(float pressure) { - if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) { - wmtab->active = (int)tablet_data->Active; - wmtab->pressure = wm_pressure_curve(tablet_data->Pressure); - wmtab->x_tilt = tablet_data->Xtilt; - wmtab->y_tilt = tablet_data->Ytilt; - /* We could have a preference to support relative tablet motion (we can't detect that). */ - wmtab->is_motion_absolute = true; - // printf("%s: using tablet %.5f\n", __func__, wmtab->pressure); + if (U.pressure_threshold_max != 0.0f) { + pressure /= U.pressure_threshold_max; + } + + CLAMP(pressure, 0.0f, 1.0f); + + if (U.pressure_softness != 0.0f) { + pressure = powf(pressure, powf(4.0f, -U.pressure_softness)); + } + + return pressure; +} + +/* adds customdata to event */ +static void update_tablet_data(wmWindow *win, wmEvent *event) +{ + const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin); + + /* if there's tablet data from an active tablet device then add it */ + if ((td != NULL) && td->Active != GHOST_kTabletModeNone) { + struct wmTabletData *wmtab = MEM_mallocN(sizeof(wmTabletData), "customdata tablet"); + + wmtab->Active = (int)td->Active; + wmtab->Pressure = wm_pressure_curve(td->Pressure); + wmtab->Xtilt = td->Xtilt; + wmtab->Ytilt = td->Ytilt; + + event->tablet_data = wmtab; + // printf("%s: using tablet %.5f\n", __func__, wmtab->Pressure); } else { - wmtab->active = EVT_TABLET_NONE; - wmtab->pressure = 1.0f; - wmtab->x_tilt = 0.0f; - wmtab->y_tilt = 0.0f; - wmtab->is_motion_absolute = false; + event->tablet_data = NULL; // printf("%s: not using tablet\n", __func__); } } @@ -4252,7 +4545,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void copy_v2_v2_int(&event.x, &cd->x); wm_stereo3d_mouse_offset_apply(win, &event.x); - wm_tablet_data_from_ghost(&cd->tablet, &event.tablet); event.prevtype = event.type; event.prevval = event.val; @@ -4260,7 +4552,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void { wmEvent *event_new = wm_event_add_mousemove(win, &event); copy_v2_v2_int(&evt->x, &event_new->x); - evt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute; + evt->is_motion_absolute = event_new->is_motion_absolute; } /* also add to other window if event is there, this makes overdraws disappear nicely */ @@ -4278,7 +4570,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void { wmEvent *event_new = wm_event_add_mousemove(owin, &oevent); copy_v2_v2_int(&oevt->x, &event_new->x); - oevt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute; + oevt->is_motion_absolute = event_new->is_motion_absolute; } } @@ -4292,9 +4584,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void pd->deltaX = -pd->deltaX; pd->deltaY = -pd->deltaY; break; - case GHOST_kTrackpadEventSmartMagnify: - event.type = MOUSESMARTZOOM; - break; case GHOST_kTrackpadEventRotate: event.type = MOUSEROTATE; break; @@ -4345,9 +4634,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void event.type = MIDDLEMOUSE; } - /* Get tablet data. */ - wm_tablet_data_from_ghost(&bd->tablet, &event.tablet); - wm_eventemulation(&event, false); /* copy previous state to prev event state (two old!) */ @@ -4358,6 +4644,17 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void evt->val = event.val; evt->type = event.type; + if (win->active == 0) { + int cx, cy; + + /* Entering window, update mouse pos. + * (ghost sends win-activate *after* the mouseclick in window!) */ + wm_get_cursor_position(win, &cx, &cy); + + event.x = evt->x = cx; + event.y = evt->y = cy; + } + /* double click test */ if (wm_event_is_double_click(&event, evt)) { CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click"); @@ -4378,7 +4675,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void oevent.y = event.y; oevent.type = event.type; oevent.val = event.val; - oevent.tablet = event.tablet; wm_event_add(owin, &oevent); } @@ -4645,29 +4941,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void #endif } -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name WM Interface Locking - * \{ */ - -/** - * Check whether operator is allowed to run in case interface is locked, - * If interface is unlocked, will always return truth. - */ -static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot) -{ - wmWindowManager *wm = CTX_wm_manager(C); - - if (wm->is_interface_locked) { - if ((ot->flag & OPTYPE_LOCK_BYPASS) == 0) { - return false; - } - } - - return true; -} - void WM_set_locked_interface(wmWindowManager *wm, bool lock) { /* This will prevent events from being handled while interface is locked @@ -4689,12 +4962,96 @@ void WM_set_locked_interface(wmWindowManager *wm, bool lock) BKE_spacedata_draw_locks(lock); } -/** \} */ +#ifdef WITH_INPUT_NDOF /* -------------------------------------------------------------------- */ -/** \name Event / Keymap Matching API +/** \name NDOF Utility Functions * \{ */ +void WM_event_ndof_pan_get(const wmNDOFMotionData *ndof, float r_pan[3], const bool use_zoom) +{ + int z_flag = use_zoom ? NDOF_ZOOM_INVERT : NDOF_PANZ_INVERT_AXIS; + r_pan[0] = ndof->tvec[0] * ((U.ndof_flag & NDOF_PANX_INVERT_AXIS) ? -1.0f : 1.0f); + r_pan[1] = ndof->tvec[1] * ((U.ndof_flag & NDOF_PANY_INVERT_AXIS) ? -1.0f : 1.0f); + r_pan[2] = ndof->tvec[2] * ((U.ndof_flag & z_flag) ? -1.0f : 1.0f); +} + +void WM_event_ndof_rotate_get(const wmNDOFMotionData *ndof, float r_rot[3]) +{ + r_rot[0] = ndof->rvec[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f); + r_rot[1] = ndof->rvec[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f); + r_rot[2] = ndof->rvec[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f); +} + +float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]) +{ + float angle; + angle = normalize_v3_v3(axis, ndof->rvec); + + axis[0] = axis[0] * ((U.ndof_flag & NDOF_ROTX_INVERT_AXIS) ? -1.0f : 1.0f); + axis[1] = axis[1] * ((U.ndof_flag & NDOF_ROTY_INVERT_AXIS) ? -1.0f : 1.0f); + axis[2] = axis[2] * ((U.ndof_flag & NDOF_ROTZ_INVERT_AXIS) ? -1.0f : 1.0f); + + return ndof->dt * angle; +} + +void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]) +{ + float axis[3]; + float angle; + + angle = WM_event_ndof_to_axis_angle(ndof, axis); + axis_angle_to_quat(q, axis, angle); +} +#endif /* WITH_INPUT_NDOF */ + +/* if this is a tablet event, return tablet pressure and set *pen_flip + * to 1 if the eraser tool is being used, 0 otherwise */ +float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2]) +{ + int erasor = 0; + float pressure = 1; + + if (tilt) { + zero_v2(tilt); + } + + if (event->tablet_data) { + const wmTabletData *wmtab = event->tablet_data; + + erasor = (wmtab->Active == EVT_TABLET_ERASER); + if (wmtab->Active != EVT_TABLET_NONE) { + pressure = wmtab->Pressure; + if (tilt) { + tilt[0] = wmtab->Xtilt; + tilt[1] = wmtab->Ytilt; + } + } + } + + if (pen_flip) { + (*pen_flip) = erasor; + } + + return pressure; +} + +bool WM_event_is_tablet(const struct wmEvent *event) +{ + return (event->tablet_data) ? true : false; +} + +#ifdef WITH_INPUT_IME +/* most os using ctrl/oskey + space to switch ime, avoid added space */ +bool WM_event_is_ime_switch(const struct wmEvent *event) +{ + return event->val == KM_PRESS && event->type == SPACEKEY && + (event->ctrl || event->oskey || event->shift || event->alt); +} +#endif + +/** \} */ + wmKeyMap *WM_event_get_keymap_from_handler(wmWindowManager *wm, wmEventHandler_Keymap *handler) { wmKeyMap *keymap; @@ -4722,10 +5079,10 @@ wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wm return NULL; } -wmKeyMapItem *WM_event_match_keymap_item_from_handlers(bContext *C, - wmWindowManager *wm, - ListBase *handlers, - const wmEvent *event) +static wmKeyMapItem *wm_kmi_from_event(bContext *C, + wmWindowManager *wm, + ListBase *handlers, + const wmEvent *event) { LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) { /* during this loop, ui handlers for nested menus can tag multiple handlers free */ @@ -4748,8 +5105,6 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(bContext *C, return NULL; } -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Cursor Keymap Status * @@ -4962,7 +5317,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) wm_eventemulation(&test_event, true); wmKeyMapItem *kmi = NULL; for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) { - kmi = WM_event_match_keymap_item_from_handlers(C, wm, handlers[handler_index], &test_event); + kmi = wm_kmi_from_event(C, wm, handlers[handler_index], &test_event); if (kmi) { break; } @@ -5058,3 +5413,43 @@ bool WM_window_modal_keymap_status_draw(bContext *UNUSED(C), wmWindow *win, uiLa } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Click/Drag Checks + * + * Values under this limit are detected as clicks. + * + * \{ */ + +int WM_event_drag_threshold(const struct wmEvent *event) +{ + int drag_threshold; + if (WM_event_is_tablet(event)) { + drag_threshold = U.drag_threshold_tablet; + } + else if (ISMOUSE(event->prevtype)) { + drag_threshold = U.drag_threshold_mouse; + } + else { + /* Typically keyboard, could be NDOF button or other less common types. */ + drag_threshold = U.drag_threshold; + } + return drag_threshold * U.dpi_fac; +} + +bool WM_event_drag_test_with_delta(const wmEvent *event, const int drag_delta[2]) +{ + const int drag_threshold = WM_event_drag_threshold(event); + return abs(drag_delta[0]) > drag_threshold || abs(drag_delta[1]) > drag_threshold; +} + +bool WM_event_drag_test(const wmEvent *event, const int prev_xy[2]) +{ + const int drag_delta[2] = { + prev_xy[0] - event->x, + prev_xy[1] - event->y, + }; + return WM_event_drag_test_with_delta(event, drag_delta); +} + +/** \} */ |