diff options
Diffstat (limited to 'source/blender')
35 files changed, 1159 insertions, 789 deletions
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 963e3158d46..9da17d777cd 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -249,6 +249,10 @@ typedef enum eAnimData_Recalc { ADT_RECALC_ALL = (ADT_RECALC_DRIVERS | ADT_RECALC_ANIM), } eAnimData_Recalc; +bool BKE_animsys_store_rna_setting(struct PointerRNA *ptr, + const char *rna_path, + const int array_index, + struct PathResolvedRNA *r_result); bool BKE_animsys_read_rna_setting(struct PathResolvedRNA *anim_rna, float *r_value); bool BKE_animsys_write_rna_setting(struct PathResolvedRNA *anim_rna, const float value); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 75e14b7efca..dd3e381ef5d 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -26,8 +26,8 @@ * * \note Use #STRINGIFY() rather than defining with quotes. */ -#define BLENDER_VERSION 282 -#define BLENDER_SUBVERSION 6 +#define BLENDER_VERSION 283 +#define BLENDER_SUBVERSION 0 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 @@ -36,7 +36,7 @@ /** Can be left blank, otherwise a,b,c... etc with no quotes. */ #define BLENDER_VERSION_CHAR /** alpha/beta/rc/release, docs use this. */ -#define BLENDER_VERSION_CYCLE beta +#define BLENDER_VERSION_CYCLE alpha /** Optionally set to 1,2,... for example to get alpha1 or rc2. */ #define BLENDER_VERSION_CYCLE_NUMBER diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 32420e2e894..be6622e5d42 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1665,11 +1665,11 @@ void BKE_keyingsets_free(ListBase *list) /* ***************************************** */ /* Evaluation Data-Setting Backend */ -static bool animsys_store_rna_setting(PointerRNA *ptr, - /* typically 'fcu->rna_path', 'fcu->array_index' */ - const char *rna_path, - const int array_index, - PathResolvedRNA *r_result) +bool BKE_animsys_store_rna_setting(PointerRNA *ptr, + /* typically 'fcu->rna_path', 'fcu->array_index' */ + const char *rna_path, + const int array_index, + PathResolvedRNA *r_result) { bool success = false; const char *path = rna_path; @@ -1880,7 +1880,7 @@ static void animsys_write_orig_anim_rna(PointerRNA *ptr, } PathResolvedRNA orig_anim_rna; /* TODO(sergey): Should be possible to cache resolved path in dependency graph somehow. */ - if (animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) { + if (BKE_animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) { BKE_animsys_write_rna_setting(&orig_anim_rna, value); } } @@ -1910,7 +1910,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, continue; } PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); BKE_animsys_write_rna_setting(&anim_rna, curval); if (flush_to_original) { @@ -1944,7 +1944,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime * NOTE: for 'layering' option later on, we should check if we should remove old value * before adding new to only be done when drivers only changed. */ PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); ok = BKE_animsys_write_rna_setting(&anim_rna, curval); } @@ -2023,7 +2023,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup * /* check if this curve should be skipped */ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0 && !BKE_fcurve_is_empty(fcu)) { PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); BKE_animsys_write_rna_setting(&anim_rna, curval); } @@ -3803,7 +3803,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) /* for each override, simply execute... */ for (aor = adt->overrides.first; aor; aor = aor->next) { PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) { BKE_animsys_write_rna_setting(&anim_rna, aor->value); } } @@ -4125,7 +4125,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, int driver_index, FCu // printf("\told val = %f\n", fcu->curval); PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { /* Evaluate driver, and write results to COW-domain destination */ const float ctime = DEG_get_ctime(depsgraph); const float curval = calculate_fcurve(&anim_rna, fcu, ctime); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 12bb7b573bd..4f0ff8bdcd3 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -1805,91 +1805,88 @@ void BKE_curve_bevel_make(Object *ob, ListBase *disp) } } else { - short dnr; - - /* bevel now in three parts, for proper vertex normals */ - /* part 1, back */ - - if ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT)) { - dnr = nr = 2 + cu->bevresol; - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - nr = 3 + 2 * cu->bevresol; - } - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->parts = 1; - dl->flag = DL_BACK_CURVE; - dl->nr = nr; - - /* half a circle */ - fp = dl->verts; - dangle = ((float)M_PI_2 / (dnr - 1)); - angle = -(nr - 1) * dangle; - - for (a = 0; a < nr; a++) { + /* The general case for nonzero extrusion or an incomplete loop. */ + dl = MEM_callocN(sizeof(DispList), "makebevelcurve"); + if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { + /* The full loop. */ + nr = 4 * cu->bevresol + 6; + dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE; + } + else if ((cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) { + /* Half the loop. */ + nr = 2 * (cu->bevresol + 1) + ((cu->ext1 == 0.0f) ? 1 : 2); + dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE; + } + else { + /* One quarter of the loop (just front or back). */ + nr = (cu->ext1 == 0.0f) ? cu->bevresol + 2 : cu->bevresol + 3; + dl->flag = (cu->flag & CU_FRONT) ? DL_FRONT_CURVE : DL_BACK_CURVE; + } + + dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve"); + BLI_addtail(disp, dl); + /* Use a different type depending on whether the loop is complete or not. */ + dl->type = ((cu->flag & (CU_FRONT | CU_BACK)) == 0) ? DL_POLY : DL_SEGM; + dl->parts = 1; + dl->nr = nr; + + fp = dl->verts; + dangle = (float)M_PI_2 / (cu->bevresol + 1); + angle = 0.0; + + /* Build the back section. */ + if (cu->flag & CU_BACK || !(cu->flag & CU_FRONT)) { + angle = (float)M_PI_2 * 3.0f; + for (a = 0; a < cu->bevresol + 2; a++) { fp[0] = 0.0; fp[1] = (float)(cosf(angle) * (cu->ext2)); fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1; angle += dangle; fp += 3; } + if ((cu->ext1 != 0.0f) && !(cu->flag & CU_FRONT) && (cu->flag & CU_BACK)) { + /* Add the extrusion if we're only building the back. */ + fp[0] = 0.0; + fp[1] = cu->ext2; + fp[2] = cu->ext1; + } } - /* part 2, sidefaces */ - if (cu->ext1 != 0.0f) { - nr = 2; - - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p2"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->parts = 1; - dl->nr = nr; - - fp = dl->verts; - fp[1] = cu->ext2; - fp[2] = -cu->ext1; - fp[4] = cu->ext2; - fp[5] = cu->ext1; - - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - dl = MEM_dupallocN(dl); - dl->verts = MEM_dupallocN(dl->verts); - BLI_addtail(disp, dl); - - fp = dl->verts; - fp[1] = -fp[1]; - fp[2] = -fp[2]; - fp[4] = -fp[4]; - fp[5] = -fp[5]; + /* Build the front section. */ + if (cu->flag & CU_FRONT || !(cu->flag & CU_BACK)) { + if ((cu->ext1 != 0.0f) && !(cu->flag & CU_BACK) && (cu->flag & CU_FRONT)) { + /* Add the extrusion if we're only building the back. */ + fp[0] = 0.0; + fp[1] = cu->ext2; + fp[2] = -cu->ext1; + fp += 3; + } + /* Don't duplicate the last back vertex. */ + angle = (cu->ext1 == 0.0f && (cu->flag & CU_BACK)) ? dangle : 0; + for (a = 0; a < cu->bevresol + 2; a++) { + fp[0] = 0.0; + fp[1] = (float)(cosf(angle) * (cu->ext2)); + fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1; + angle += dangle; + fp += 3; } } - /* part 3, front */ - if ((cu->flag & CU_FRONT) || !(cu->flag & CU_BACK)) { - dnr = nr = 2 + cu->bevresol; - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - nr = 3 + 2 * cu->bevresol; + /* Build the other half only if we're building the full loop. */ + if (!(cu->flag & (CU_FRONT | CU_BACK))) { + for (a = 0; a < cu->bevresol + 1; a++) { + fp[0] = 0.0; + fp[1] = (float)(cosf(angle) * (cu->ext2)); + fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1; + angle += dangle; + fp += 3; } - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p3"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->flag = DL_FRONT_CURVE; - dl->parts = 1; - dl->nr = nr; - - /* half a circle */ - fp = dl->verts; - angle = 0.0; - dangle = ((float)M_PI_2 / (dnr - 1)); - for (a = 0; a < nr; a++) { + angle = (float)M_PI; + for (a = 0; a < cu->bevresol + 1; a++) { fp[0] = 0.0; fp[1] = (float)(cosf(angle) * (cu->ext2)); - fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1; + fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1; angle += dangle; fp += 3; } diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 3e449fa6b25..f58c20a7d72 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -247,8 +247,12 @@ WorkSpaceLayout *BKE_workspace_layout_add(Main *bmain, void BKE_workspace_layout_remove(Main *bmain, WorkSpace *workspace, WorkSpaceLayout *layout) { - id_us_min(&layout->screen->id); - BKE_id_free(bmain, layout->screen); + /* Screen should usually be set, but we call this from file reading to get rid of invalid + * layouts. */ + if (layout->screen) { + id_us_min(&layout->screen->id); + BKE_id_free(bmain, layout->screen); + } BLI_freelinkN(&workspace->layouts, layout); } diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h index e3cd70f7413..fdb4fe30f1c 100644 --- a/source/blender/blenlib/BLI_rect.h +++ b/source/blender/blenlib/BLI_rect.h @@ -39,6 +39,10 @@ bool BLI_rcti_is_empty(const struct rcti *rect); bool BLI_rctf_is_empty(const struct rctf *rect); void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax); void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax); +bool BLI_rctf_is_valid(const struct rctf *rect); +bool BLI_rcti_is_valid(const struct rcti *rect); +void BLI_rctf_sanitize(struct rctf *rect); +void BLI_rcti_sanitize(struct rcti *rect); void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size); void BLI_rcti_init_pt_radius(struct rcti *rect, const int xy[2], int size); void BLI_rcti_init_minmax(struct rcti *rect); diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c index ecff2ebffef..8fab4ed8e6a 100644 --- a/source/blender/blenlib/intern/rct.c +++ b/source/blender/blenlib/intern/rct.c @@ -439,42 +439,66 @@ void BLI_rcti_union(rcti *rct1, const rcti *rct2) void BLI_rctf_init(rctf *rect, float xmin, float xmax, float ymin, float ymax) { - if (xmin <= xmax) { - rect->xmin = xmin; - rect->xmax = xmax; - } - else { - rect->xmax = xmin; - rect->xmin = xmax; - } - if (ymin <= ymax) { - rect->ymin = ymin; - rect->ymax = ymax; - } - else { - rect->ymax = ymin; - rect->ymin = ymax; - } + rect->xmin = xmin; + rect->xmax = xmax; + rect->ymin = ymin; + rect->ymax = ymax; + + BLI_rctf_sanitize(rect); } void BLI_rcti_init(rcti *rect, int xmin, int xmax, int ymin, int ymax) { - if (xmin <= xmax) { - rect->xmin = xmin; - rect->xmax = xmax; + rect->xmin = xmin; + rect->xmax = xmax; + rect->ymin = ymin; + rect->ymax = ymax; + + BLI_rcti_sanitize(rect); +} + +/** + * Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively. + * If this returns false, #BLI_rctf_sanitize() can be called to address this. + * + * This is not a hard constraint or invariant for rectangles, in some cases it may be useful to + * have max < min. Usually this is what you'd want though. + */ +bool BLI_rctf_is_valid(const rctf *rect) +{ + return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax); +} + +bool BLI_rcti_is_valid(const rcti *rect) +{ + return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax); +} + +/** + * Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively. + */ +void BLI_rctf_sanitize(rctf *rect) +{ + if (rect->xmin > rect->xmax) { + SWAP(float, rect->xmin, rect->xmax); } - else { - rect->xmax = xmin; - rect->xmin = xmax; + if (rect->ymin > rect->ymax) { + SWAP(float, rect->ymin, rect->ymax); } - if (ymin <= ymax) { - rect->ymin = ymin; - rect->ymax = ymax; + + BLI_assert(BLI_rctf_is_valid(rect)); +} + +void BLI_rcti_sanitize(rcti *rect) +{ + if (rect->xmin > rect->xmax) { + SWAP(int, rect->xmin, rect->xmax); } - else { - rect->ymax = ymin; - rect->ymin = ymax; + if (rect->ymin > rect->ymax) { + SWAP(int, rect->ymin, rect->ymax); } + + BLI_assert(BLI_rcti_is_valid(rect)); } void BLI_rctf_init_pt_radius(rctf *rect, const float xy[2], float size) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 0ebff916cf9..6a54fc8f59e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3371,6 +3371,11 @@ static void lib_link_workspaces(FileData *fd, Main *bmain) } } } + else { + /* If we're reading a layout without screen stored, it's useless and we shouldn't keep it + * around. */ + BKE_workspace_layout_remove(bmain, workspace, layout); + } } id->tag &= ~LIB_TAG_NEED_LINK; diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index 4abeec19645..7f3c7d5043f 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -59,6 +59,7 @@ set(SRC intern/eval/deg_eval_copy_on_write.cc intern/eval/deg_eval_flush.cc intern/eval/deg_eval_runtime_backup.cc + intern/eval/deg_eval_runtime_backup_animation.cc intern/eval/deg_eval_runtime_backup_modifier.cc intern/eval/deg_eval_runtime_backup_movieclip.cc intern/eval/deg_eval_runtime_backup_object.cc @@ -108,6 +109,7 @@ set(SRC intern/eval/deg_eval_copy_on_write.h intern/eval/deg_eval_flush.h intern/eval/deg_eval_runtime_backup.h + intern/eval/deg_eval_runtime_backup_animation.h intern/eval/deg_eval_runtime_backup_modifier.h intern/eval/deg_eval_runtime_backup_movieclip.h intern/eval/deg_eval_runtime_backup_object.h diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 3e0ab9684da..31c1b0361f8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -2674,6 +2674,26 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) BLI_assert(object->type == OB_EMPTY); } } + +#if 0 + /* NOTE: Relation is disabled since AnimationBackup() is disabled. + * See comment in AnimationBackup:init_from_id(). */ + + /* Copy-on-write of write will iterate over f-curves to store current values corresponding + * to their RNA path. This means that action must be copied prior to the ID's copy-on-write, + * otherwise depsgraph might try to access freed data. */ + AnimData *animation_data = BKE_animdata_from_id(id_orig); + if (animation_data != NULL) { + if (animation_data->action != NULL) { + OperationKey action_copy_on_write_key( + &animation_data->action->id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); + add_relation(action_copy_on_write_key, + copy_on_write_key, + "Eval Order", + RELATION_FLAG_GODMODE | RELATION_FLAG_NO_FLUSH); + } + } +#endif } /* **** ID traversal callbacks functions **** */ diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc index 88390ab412f..4da5ca77fb8 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc @@ -32,7 +32,8 @@ namespace DEG { RuntimeBackup::RuntimeBackup(const Depsgraph *depsgraph) - : scene_backup(depsgraph), + : animation_backup(depsgraph), + scene_backup(depsgraph), sound_backup(depsgraph), object_backup(depsgraph), drawdata_ptr(NULL), @@ -47,6 +48,8 @@ void RuntimeBackup::init_from_id(ID *id) return; } + animation_backup.init_from_id(id); + const ID_Type id_type = GS(id->name); switch (id_type) { case ID_OB: @@ -76,6 +79,8 @@ void RuntimeBackup::init_from_id(ID *id) void RuntimeBackup::restore_to_id(ID *id) { + animation_backup.restore_to_id(id); + const ID_Type id_type = GS(id->name); switch (id_type) { case ID_OB: diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h index 31ae3164e37..892cc88002f 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h @@ -25,6 +25,7 @@ #include "DNA_ID.h" +#include "intern/eval/deg_eval_runtime_backup_animation.h" #include "intern/eval/deg_eval_runtime_backup_movieclip.h" #include "intern/eval/deg_eval_runtime_backup_object.h" #include "intern/eval/deg_eval_runtime_backup_scene.h" @@ -44,6 +45,7 @@ class RuntimeBackup { /* Restore fields to the given ID. */ void restore_to_id(ID *id); + AnimationBackup animation_backup; SceneBackup scene_backup; SoundBackup sound_backup; ObjectRuntimeBackup object_backup; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc new file mode 100644 index 00000000000..cc4935431d1 --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc @@ -0,0 +1,144 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#include "intern/eval/deg_eval_runtime_backup_animation.h" + +#include "DNA_anim_types.h" + +#include "BKE_animsys.h" + +#include "RNA_access.h" +#include "RNA_types.h" + +#include "intern/depsgraph.h" + +namespace DEG { + +namespace { + +struct AnimatedPropertyStoreCalbackData { + AnimationBackup *backup; + + /* ID which needs to be stored. + * Is used to check possibly nested IDs which f-curves are pointing to. */ + ID *id; + + PointerRNA id_pointer_rna; +}; + +void animated_property_store_cb(ID *id, FCurve *fcurve, void *data_v) +{ + AnimatedPropertyStoreCalbackData *data = reinterpret_cast<AnimatedPropertyStoreCalbackData *>( + data_v); + if (fcurve->rna_path == NULL || fcurve->rna_path[0] == '\0') { + return; + } + if (id != data->id) { + return; + } + + /* Resolve path to the property. */ + PathResolvedRNA resolved_rna; + if (!BKE_animsys_store_rna_setting( + &data->id_pointer_rna, fcurve->rna_path, fcurve->array_index, &resolved_rna)) { + return; + } + + /* Read property value. */ + float value; + if (!BKE_animsys_read_rna_setting(&resolved_rna, &value)) { + return; + } + + data->backup->values_backup.emplace_back(fcurve->rna_path, fcurve->array_index, value); +} + +} // namespace + +AnimationValueBackup::AnimationValueBackup() +{ +} + +AnimationValueBackup::AnimationValueBackup(const string &rna_path, int array_index, float value) + : rna_path(rna_path), array_index(array_index), value(value) +{ +} + +AnimationValueBackup::~AnimationValueBackup() +{ +} + +AnimationBackup::AnimationBackup(const Depsgraph *depsgraph) +{ + meed_value_backup = !depsgraph->is_active; + reset(); +} + +void AnimationBackup::reset() +{ +} + +void AnimationBackup::init_from_id(ID *id) +{ + /* NOTE: This animation backup nicely preserves values which are animated and + * are not touched by frame/depsgraph post_update handler. + * + * But it makes it impossible to have user edits to animated properties: for + * example, translation of object with animated location will not work with + * the current version of backup. */ + return; + + AnimatedPropertyStoreCalbackData data; + data.backup = this; + data.id = id; + RNA_id_pointer_create(id, &data.id_pointer_rna); + BKE_fcurves_id_cb(id, animated_property_store_cb, &data); +} + +void AnimationBackup::restore_to_id(ID *id) +{ + return; + + PointerRNA id_pointer_rna; + RNA_id_pointer_create(id, &id_pointer_rna); + for (const AnimationValueBackup &value_backup : values_backup) { + /* Resolve path to the property. + * + * NOTE: Do it again (after storing), since the sub-data pointers might be + * changed after copy-on-write. */ + PathResolvedRNA resolved_rna; + if (!BKE_animsys_store_rna_setting(&id_pointer_rna, + value_backup.rna_path.c_str(), + value_backup.array_index, + &resolved_rna)) { + return; + } + + /* Write property value. */ + if (!BKE_animsys_write_rna_setting(&resolved_rna, value_backup.value)) { + return; + } + } +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h new file mode 100644 index 00000000000..d97ee2b0556 --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h @@ -0,0 +1,65 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#pragma once + +#include "BKE_modifier.h" + +#include "intern/depsgraph_type.h" + +namespace DEG { + +struct Depsgraph; + +class AnimationValueBackup { + public: + AnimationValueBackup(); + AnimationValueBackup(const string &rna_path, int array_index, float value); + ~AnimationValueBackup(); + + AnimationValueBackup(const AnimationValueBackup &other) = default; + AnimationValueBackup(AnimationValueBackup &&other) noexcept = default; + + AnimationValueBackup &operator=(const AnimationValueBackup &other) = default; + AnimationValueBackup &operator=(AnimationValueBackup &&other) = default; + + string rna_path; + int array_index; + float value; +}; + +/* Backup of animated properties values. */ +class AnimationBackup { + public: + AnimationBackup(const Depsgraph *depsgraph); + + void reset(); + + void init_from_id(ID *id); + void restore_to_id(ID *id); + + bool meed_value_backup; + vector<AnimationValueBackup> values_backup; +}; + +} // namespace DEG diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c index 70a9b7ba1fa..ae489fb5233 100644 --- a/source/blender/editors/animation/time_scrub_ui.c +++ b/source/blender/editors/animation/time_scrub_ui.c @@ -179,9 +179,9 @@ void ED_time_scrub_channel_search_draw(const bContext *C, ARegion *ar, bDopeShee rcti rect; rect.xmin = 0; - rect.xmax = ceilf(ar->sizex * UI_DPI_FAC); - rect.ymin = ar->sizey * UI_DPI_FAC - UI_TIME_SCRUB_MARGIN_Y; - rect.ymax = ceilf(ar->sizey * UI_DPI_FAC); + rect.xmax = ar->winx; + rect.ymin = ar->winy - UI_TIME_SCRUB_MARGIN_Y; + rect.ymax = ar->winy; uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 52696475c20..68cd450a451 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -2436,6 +2436,10 @@ void uiItemEnumR_string_prop(uiLayout *layout, } for (a = 0; item[a].identifier; a++) { + if (item[a].identifier[0] == '\0') { + /* Skip enum item separators. */ + continue; + } if (item[a].value == ivalue) { const char *item_name = name ? name : diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 8012565ba2e..34e1b3b2b4b 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -218,7 +218,7 @@ static int object_hide_view_set_exec(bContext *C, wmOperator *op) /* Hide selected or unselected objects. */ for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (!(base->flag & BASE_VISIBLE_DEPSGRAPH)) { + if (!(base->flag & BASE_VISIBLE_VIEWLAYER)) { continue; } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 29626fb6a8f..f4d9c353102 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1244,6 +1244,20 @@ static void region_rect_recursive( alignment = RGN_ALIGN_NONE; } + /* If both the ARegion.sizex/y and the prefsize are 0, the region is tagged as too small, even + * before the layout for dynamic regions is created. #wm_draw_window_offscreen() allows the + * layout to be created despite the RGN_FLAG_TOO_SMALL flag being set. But there may still be + * regions that don't have a separate ARegionType.layout callback. For those, set a default + * prefsize so they can become visible. */ + if ((ar->flag & RGN_FLAG_DYNAMIC_SIZE) && !(ar->type->layout)) { + if ((ar->sizex == 0) && (ar->type->prefsizex == 0)) { + ar->type->prefsizex = AREAMINX; + } + if ((ar->sizey == 0) && (ar->type->prefsizey == 0)) { + ar->type->prefsizey = HEADERY; + } + } + /* prefsize, taking into account DPI */ int prefsizex = UI_DPI_FAC * ((ar->sizex > 1) ? ar->sizex + 0.5f : ar->type->prefsizex); int prefsizey; @@ -1323,7 +1337,7 @@ static void region_rect_recursive( else if (alignment == RGN_ALIGN_TOP || alignment == RGN_ALIGN_BOTTOM) { rcti *winrct = (ar->overlap) ? overlap_remainder : remainder; - if (rct_fits(winrct, 'v', prefsizey) < 0) { + if ((prefsizey == 0) || (rct_fits(winrct, 'v', prefsizey) < 0)) { ar->flag |= RGN_FLAG_TOO_SMALL; } else { @@ -1348,7 +1362,7 @@ static void region_rect_recursive( else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) { rcti *winrct = (ar->overlap) ? overlap_remainder : remainder; - if (rct_fits(winrct, 'h', prefsizex) < 0) { + if ((prefsizex == 0) || (rct_fits(winrct, 'h', prefsizex) < 0)) { ar->flag |= RGN_FLAG_TOO_SMALL; } else { @@ -1438,9 +1452,8 @@ static void region_rect_recursive( } /* Fix any negative dimensions. This can happen when a quad split 3d view gets to small. (see - * T72200). BLI_rcti_init() sanitizes, making sure min values are <= max values. */ - BLI_rcti_init( - &ar->winrct, ar->winrct.xmin, ar->winrct.xmax, ar->winrct.ymin, ar->winrct.ymax); + * T72200). */ + BLI_rcti_sanitize(&ar->winrct); quad++; } @@ -1479,11 +1492,16 @@ static void region_rect_recursive( ar->winrct.xmin = ar->winrct.xmax; break; case RGN_ALIGN_LEFT: + ar->winrct.xmax = ar->winrct.xmin; + break; default: /* prevent winrct to be valid */ ar->winrct.xmax = ar->winrct.xmin; break; } + + /* Size on one axis is now 0, the other axis may still be invalid (negative) though. */ + BLI_rcti_sanitize(&ar->winrct); } /* restore prev-split exception */ @@ -1501,6 +1519,8 @@ static void region_rect_recursive( *overlap_remainder = *remainder; } + BLI_assert(BLI_rcti_is_valid(&ar->winrct)); + region_rect_recursive(sa, ar->next, remainder, overlap_remainder, quad); /* Tag for redraw if size changes. */ @@ -2902,7 +2922,7 @@ void ED_region_info_draw(ARegion *ar, float fill_color[4], const bool full_redraw) { - ED_region_info_draw_multiline(ar, (const char * [2]){text, NULL}, fill_color, full_redraw); + ED_region_info_draw_multiline(ar, (const char *[2]){text, NULL}, fill_color, full_redraw); } #define MAX_METADATA_STR 1024 diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 16305a9b17b..04c939ec41b 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -1083,11 +1083,7 @@ static void graph_region_draw(const bContext *C, ARegion *ar) /* scale indicators */ { rcti rect; - BLI_rcti_init(&rect, - 0, - 15 * UI_DPI_FAC, - 15 * UI_DPI_FAC, - UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y); + BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y); UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_TEXT); } } diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 03df93e4c8a..98fe8c71454 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -298,7 +298,7 @@ static int graphkeys_viewall(bContext *C, if (!BLI_listbase_is_empty(ED_context_get_markers(C))) { pad_bottom = UI_MARKER_MARGIN_Y; } - BLI_rctf_pad_y(&cur_new, ac.ar->sizey * UI_DPI_FAC, pad_bottom, pad_top); + BLI_rctf_pad_y(&cur_new, ac.ar->winy, pad_bottom, pad_top); UI_view2d_smooth_view(C, ac.ar, &cur_new, smooth_viewtx); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index 7bc907bb3db..d01e4112fd0 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -326,11 +326,7 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar) /* scale numbers */ { rcti rect; - BLI_rcti_init(&rect, - 0, - 15 * UI_DPI_FAC, - 15 * UI_DPI_FAC, - UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y); + BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y); UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_SCROLL_TEXT); } } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 70cb28fa937..333a51e2eac 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -2119,11 +2119,7 @@ void draw_timeline_seq(const bContext *C, ARegion *ar) /* channel numbers */ { rcti rect; - BLI_rcti_init(&rect, - 0, - 15 * UI_DPI_FAC, - 15 * UI_DPI_FAC, - UI_DPI_FAC * ar->sizey - UI_TIME_SCRUB_MARGIN_Y); + BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, ar->winy - UI_TIME_SCRUB_MARGIN_Y); UI_view2d_draw_scale_y__block(ar, v2d, &rect, TH_SCROLL_TEXT); } } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 9a98a2b8a00..62a61a3a05a 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -856,7 +856,7 @@ static bool transform_modal_item_poll(const wmOperator *op, int value) if (t->spacetype != SPACE_VIEW3D) { return false; } - else if (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) { + else if ((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) == 0) { return false; } else if (!validSnap(t)) { diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index a8e8ca72023..19c7386ad6d 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -188,7 +188,6 @@ GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint bu GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode); GPUTexture *GPU_texture_from_blender(struct Image *ima, struct ImageUser *iuser, int textarget); -GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap); /* movie clip drawing */ GPUTexture *GPU_texture_from_movieclip(struct MovieClip *clip, diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 201194232db..84328b8dfd4 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -1064,56 +1064,6 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode) return tex; } -GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) -{ - GPUTexture *tex = prv->gputexture[0]; - GLuint bindcode = 0; - - if (tex) { - bindcode = tex->bindcode; - } - - /* this binds a texture, so that's why we restore it to 0 */ - if (bindcode == 0) { - GPU_create_gl_tex( - &bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], GL_TEXTURE_2D, mipmap, false, NULL); - } - if (tex) { - tex->bindcode = bindcode; - glBindTexture(GL_TEXTURE_2D, 0); - return tex; - } - - tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->bindcode = bindcode; - tex->number = -1; - tex->refcount = 1; - tex->target = GL_TEXTURE_2D; - tex->target_base = GL_TEXTURE_2D; - tex->format = -1; - tex->components = -1; - - prv->gputexture[0] = tex; - - if (!glIsTexture(tex->bindcode)) { - GPU_print_error_debug("Blender Texture Not Loaded"); - } - else { - GLint w, h; - - glBindTexture(GL_TEXTURE_2D, tex->bindcode); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); - - tex->w = w; - tex->h = h; - } - - glBindTexture(GL_TEXTURE_2D, 0); - - return tex; -} - GPUTexture *GPU_texture_create_1d(int w, eGPUTextureFormat tex_format, const float *pixels, diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index d3c5a707b44..60fb7b62dff 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -409,7 +409,9 @@ typedef struct ARegion { short flag; /** Current split size in unscaled pixels (if zero it uses regiontype). - * To convert to pixels use: `UI_DPI_FAC * ar->sizex + 0.5f`. */ + * To convert to pixels use: `UI_DPI_FAC * ar->sizex + 0.5f`. + * However to get the current region size, you should usually use winx/winy from above, not this! + */ short sizex, sizey; /** Private, cached notifier events. */ diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index ab87f81dba5..d84b0f795ec 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -54,6 +54,7 @@ set(SRC intern/wm_cursors.c intern/wm_dragdrop.c intern/wm_draw.c + intern/wm_event_query.c intern/wm_event_system.c intern/wm_files.c intern/wm_files_link.c diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index d24157a22a6..02685cfb555 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -207,10 +207,6 @@ void WM_cursor_warp(struct wmWindow *win, int x, int y); void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y); float WM_cursor_pressure(const struct wmWindow *win); -/* event map */ -int WM_userdef_event_map(int kmitype); -int WM_userdef_event_type_from_keymap_type(int kmitype); - /* handlers */ typedef bool (*EventHandlerPoll)(const ARegion *ar, const struct wmEvent *event); @@ -250,6 +246,11 @@ wmKeyMapItem *WM_event_match_keymap_item(struct bContext *C, wmKeyMap *keymap, const struct wmEvent *event); +wmKeyMapItem *WM_event_match_keymap_item_from_handlers(struct bContext *C, + struct wmWindowManager *wm, + struct ListBase *handlers, + const struct wmEvent *event); + typedef int (*wmUIHandlerFunc)(struct bContext *C, const struct wmEvent *event, void *userdata); typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata); @@ -294,8 +295,6 @@ struct wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers, /* mouse */ void WM_event_add_mousemove(const struct bContext *C); -bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event); -bool WM_event_is_last_mousemove(const struct wmEvent *event); #ifdef WITH_INPUT_NDOF /* 3D mouse */ @@ -631,15 +630,9 @@ bool WM_gesture_is_modal_first(const struct wmGesture *gesture); /* fileselecting support */ void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op); void WM_event_fileselect_event(struct wmWindowManager *wm, void *ophandle, int eventval); -int WM_event_modifier_flag(const struct wmEvent *event); -void WM_event_print(const struct wmEvent *event); void WM_operator_region_active_win_set(struct bContext *C); -int WM_event_drag_threshold(const struct wmEvent *event); -bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]); -bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]); - /* drag and drop */ struct wmDrag *WM_event_start_drag( struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags); @@ -783,6 +776,36 @@ bool write_crash_blend(void); /* Lock the interface for any communication */ void WM_set_locked_interface(struct wmWindowManager *wm, bool lock); +/* For testing only 'G_FLAG_EVENT_SIMULATE' */ +struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add); + +const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win, + int button_index, + int type_index); +void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win); + +void WM_window_status_area_tag_redraw(struct wmWindow *win); +struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *sc); +bool WM_window_modal_keymap_status_draw(struct bContext *C, + struct wmWindow *win, + struct uiLayout *layout); + +/* wm_event_query.c */ +void WM_event_print(const struct wmEvent *event); + +int WM_event_modifier_flag(const struct wmEvent *event); + +bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event); +bool WM_event_is_last_mousemove(const struct wmEvent *event); + +int WM_event_drag_threshold(const struct wmEvent *event); +bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]); +bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]); + +/* event map */ +int WM_userdef_event_map(int kmitype); +int WM_userdef_event_type_from_keymap_type(int kmitype); + #ifdef WITH_INPUT_NDOF void WM_event_ndof_pan_get(const struct wmNDOFMotionData *ndof, float r_pan[3], @@ -800,20 +823,6 @@ bool WM_event_is_tablet(const struct wmEvent *event); bool WM_event_is_ime_switch(const struct wmEvent *event); #endif -/* For testing only 'G_FLAG_EVENT_SIMULATE' */ -struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add); - -const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win, - int button_index, - int type_index); -void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win); - -void WM_window_status_area_tag_redraw(struct wmWindow *win); -struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *sc); -bool WM_window_modal_keymap_status_draw(struct bContext *C, - struct wmWindow *win, - struct uiLayout *layout); - /* wm_tooltip.c */ typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *C, struct ARegion *ar, diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 0c3a5f92113..e9e4b7c6d12 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -548,9 +548,6 @@ typedef struct wmEvent { char check_drag; char is_motion_absolute; - /** Keymap item, set by handler (weak?). */ - const char *keymap_idname; - /** Tablet info, only use when the tablet is active. */ const struct wmTabletData *tablet_data; diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 09b7d89fc2b..14d4e05b77a 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -581,7 +581,14 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo) /* Compute UI layouts for dynamically size regions. */ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->visible && ar->do_draw && ar->type && ar->type->layout) { + /* Dynamic region may have been flagged as too small because their size on init is 0. + * ARegion.visible is false then, as expected. The layout should still be created then, so + * the region size can be updated (it may turn out to be not too small then). */ + const bool ignore_visibility = (ar->flag & RGN_FLAG_DYNAMIC_SIZE) && + (ar->flag & RGN_FLAG_TOO_SMALL) && + !(ar->flag & RGN_FLAG_HIDDEN); + + if ((ar->visible || ignore_visibility) && ar->do_draw && ar->type && ar->type->layout) { CTX_wm_region_set(C, ar); ED_region_do_layout(C, ar); CTX_wm_region_set(C, NULL); diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c new file mode 100644 index 00000000000..86d92a473ff --- /dev/null +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -0,0 +1,442 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + * + * Read-only queries utility functions for the event system. + */ + +#include <stdlib.h> +#include <string.h> + +#include "DNA_listBase.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_userdef_types.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "BKE_context.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "wm_event_system.h" +#include "wm_event_types.h" + +#include "RNA_enum_types.h" + +#include "DEG_depsgraph.h" + +/* -------------------------------------------------------------------- */ +/** \name Event Printing + * \{ */ + +/* for debugging only, getting inspecting events manually is tedious */ +void WM_event_print(const wmEvent *event) +{ + if (event) { + const char *unknown = "UNKNOWN"; + const char *type_id = unknown; + const char *val_id = unknown; + + RNA_enum_identifier(rna_enum_event_type_items, event->type, &type_id); + RNA_enum_identifier(rna_enum_event_value_items, event->val, &val_id); + + printf( + "wmEvent type:%d / %s, val:%d / %s,\n" + " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n" + " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n", + event->type, + type_id, + event->val, + val_id, + event->shift, + event->ctrl, + event->alt, + event->oskey, + event->keymodifier, + event->x, + event->y, + event->ascii, + BLI_str_utf8_size(event->utf8_buf), + event->utf8_buf, + (const void *)event); + +#ifdef WITH_INPUT_NDOF + if (ISNDOF(event->type)) { + const wmNDOFMotionData *ndof = event->customdata; + if (event->type == NDOF_MOTION) { + printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n", + UNPACK3(ndof->rvec), + UNPACK3(ndof->tvec), + ndof->dt, + ndof->progress); + } + else { + /* ndof buttons printed already */ + } + } +#endif /* WITH_INPUT_NDOF */ + + if (event->tablet_data) { + const wmTabletData *wmtab = event->tablet_data; + printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n", + wmtab->Active, + wmtab->Pressure, + wmtab->Xtilt, + wmtab->Ytilt); + } + } + else { + printf("wmEvent - NULL\n"); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Modifier/Type Queries + * \{ */ + +int WM_event_modifier_flag(const wmEvent *event) +{ + int flag = 0; + if (event->ctrl) { + flag |= KM_CTRL; + } + if (event->alt) { + flag |= KM_ALT; + } + if (event->shift) { + flag |= KM_SHIFT; + } + if (event->oskey) { + flag |= KM_OSKEY; + } + return flag; +} + +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; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Motion Queries + * \{ */ + +/* 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_is_last_mousemove(const wmEvent *event) +{ + while ((event = event->next)) { + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + return false; + } + } + return true; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \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); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Preference Mapping + * \{ */ + +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; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event NDOF Input Access + * \{ */ + +#ifdef WITH_INPUT_NDOF + +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 */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Tablet Input Access + * \{ */ + +/* applies the global tablet pressure correction curve */ +float wm_pressure_curve(float 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; +} + +/* 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; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event IME Input Access + * \{ */ + +#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 + +/** \} */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index f5970e8fb61..d90eab6f94f 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -70,7 +70,6 @@ #include "RNA_access.h" #include "UI_interface.h" -#include "UI_view2d.h" #include "PIL_time.h" @@ -84,8 +83,6 @@ #include "wm_event_system.h" #include "wm_event_types.h" -#include "RNA_enum_types.h" - #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -114,6 +111,8 @@ 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 * \{ */ @@ -682,6 +681,82 @@ static void wm_handler_ui_cancel(bContext *C) /** \} */ /* -------------------------------------------------------------------- */ +/** \name WM Reports + * + * Access to #wmWindowManager.reports + * \{ */ + +/** + * Show the report in the info header. + */ +void WM_report_banner_show(void) +{ + wmWindowManager *wm = G_MAIN->wm.first; + ReportList *wm_reports = &wm->reports; + ReportTimerInfo *rti; + + /* After adding reports to the global list, reset the report timer. */ + WM_event_remove_timer(wm, NULL, wm_reports->reporttimer); + + /* Records time since last report was added */ + wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05); + + rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo"); + wm_reports->reporttimer->customdata = rti; +} + +#ifdef WITH_INPUT_NDOF +void WM_ndof_deadzone_set(float deadzone) +{ + GHOST_setNDOFDeadZone(deadzone); +} +#endif + +static void wm_add_reports(ReportList *reports) +{ + /* if the caller owns them, handle this */ + if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) { + wmWindowManager *wm = G_MAIN->wm.first; + + /* add reports to the global list, otherwise they are not seen */ + BLI_movelisttolist(&wm->reports.list, &reports->list); + + WM_report_banner_show(); + } +} + +void WM_report(ReportType type, const char *message) +{ + ReportList reports; + + BKE_reports_init(&reports, RPT_STORE); + BKE_report(&reports, type, message); + + wm_add_reports(&reports); + + BKE_reports_clear(&reports); +} + +void WM_reportf(ReportType type, const char *format, ...) +{ + DynStr *ds; + va_list args; + + ds = BLI_dynstr_new(); + va_start(args, format); + BLI_dynstr_vappendf(ds, format, args); + va_end(args); + + char *str = BLI_dynstr_get_cstring(ds); + WM_report(type, str); + MEM_freeN(str); + + BLI_dynstr_free(ds); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Operator Logic * \{ */ @@ -762,164 +837,6 @@ void WM_operator_region_active_win_set(bContext *C) } } -int WM_event_modifier_flag(const wmEvent *event) -{ - int flag = 0; - if (event->ctrl) { - flag |= KM_CTRL; - } - if (event->alt) { - flag |= KM_ALT; - } - if (event->shift) { - flag |= KM_SHIFT; - } - if (event->oskey) { - flag |= KM_OSKEY; - } - return flag; -} - -/* for debugging only, getting inspecting events manually is tedious */ -void WM_event_print(const wmEvent *event) -{ - if (event) { - const char *unknown = "UNKNOWN"; - const char *type_id = unknown; - const char *val_id = unknown; - - RNA_enum_identifier(rna_enum_event_type_items, event->type, &type_id); - RNA_enum_identifier(rna_enum_event_value_items, event->val, &val_id); - - printf( - "wmEvent type:%d / %s, val:%d / %s,\n" - " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n" - " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', keymap_idname:%s, pointer:%p\n", - event->type, - type_id, - event->val, - val_id, - event->shift, - event->ctrl, - event->alt, - event->oskey, - event->keymodifier, - event->x, - event->y, - event->ascii, - BLI_str_utf8_size(event->utf8_buf), - event->utf8_buf, - event->keymap_idname, - (const void *)event); - -#ifdef WITH_INPUT_NDOF - if (ISNDOF(event->type)) { - const wmNDOFMotionData *ndof = event->customdata; - if (event->type == NDOF_MOTION) { - printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n", - UNPACK3(ndof->rvec), - UNPACK3(ndof->tvec), - ndof->dt, - ndof->progress); - } - else { - /* ndof buttons printed already */ - } - } -#endif /* WITH_INPUT_NDOF */ - - if (event->tablet_data) { - const wmTabletData *wmtab = event->tablet_data; - printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n", - wmtab->Active, - wmtab->Pressure, - wmtab->Xtilt, - wmtab->Ytilt); - } - } - else { - printf("wmEvent - NULL\n"); - } -} - -/** - * Show the report in the info header. - */ -void WM_report_banner_show(void) -{ - wmWindowManager *wm = G_MAIN->wm.first; - ReportList *wm_reports = &wm->reports; - ReportTimerInfo *rti; - - /* After adding reports to the global list, reset the report timer. */ - WM_event_remove_timer(wm, NULL, wm_reports->reporttimer); - - /* Records time since last report was added */ - wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05); - - rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo"); - wm_reports->reporttimer->customdata = rti; -} - -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) -{ - GHOST_setNDOFDeadZone(deadzone); -} -#endif - -static void wm_add_reports(ReportList *reports) -{ - /* if the caller owns them, handle this */ - if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) { - wmWindowManager *wm = G_MAIN->wm.first; - - /* add reports to the global list, otherwise they are not seen */ - BLI_movelisttolist(&wm->reports.list, &reports->list); - - WM_report_banner_show(); - } -} - -void WM_report(ReportType type, const char *message) -{ - ReportList reports; - - BKE_reports_init(&reports, RPT_STORE); - BKE_report(&reports, type, message); - - wm_add_reports(&reports); - - BKE_reports_clear(&reports); -} - -void WM_reportf(ReportType type, const char *format, ...) -{ - DynStr *ds; - va_list args; - - ds = BLI_dynstr_new(); - va_start(args, format); - BLI_dynstr_vappendf(ds, format, args); - va_end(args); - - char *str = BLI_dynstr_get_cstring(ds); - WM_report(type, str); - MEM_freeN(str); - - BLI_dynstr_free(ds); -} - /* (caller_owns_reports == true) when called from python */ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool caller_owns_reports) { @@ -1301,105 +1218,6 @@ 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. */ @@ -1954,42 +1772,6 @@ 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) { @@ -2103,10 +1885,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(const bContext *C, - wmOperator *op, - wmEvent *event, - bool *dbl_click_disabled) +static void wm_event_modalkeymap_begin(const bContext *C, + wmOperator *op, + wmEvent *event, + bool *dbl_click_disabled) { BLI_assert(event->type != EVT_MODAL_MAP); @@ -2159,25 +1941,13 @@ static void wm_event_modalkeymap(const bContext *C, } /** - * Check whether operator is allowed to run in case interface is locked, - * If interface is unlocked, will always return truth. + * 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). */ -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) +static void wm_event_modalkeymap_end(wmEvent *event, bool dbl_click_disabled) { if (event->type == EVT_MODAL_MAP) { event->type = event->prevtype; @@ -2196,7 +1966,8 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler_base, wmEvent *event, - PointerRNA *properties) + PointerRNA *properties, + const char *kmi_idname) { int retval = OPERATOR_PASS_THROUGH; @@ -2221,7 +1992,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(C, op, event, &dbl_click_disabled); + wm_event_modalkeymap_begin(C, op, event, &dbl_click_disabled); if (ot->flag & OPTYPE_UNDO) { wm->op_undo_depth++; @@ -2236,7 +2007,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_modalmap_end(event, dbl_click_disabled); + wm_event_modalkeymap_end(event, dbl_click_disabled); if (ot->flag & OPTYPE_UNDO) { wm->op_undo_depth--; @@ -2298,7 +2069,7 @@ static int wm_handler_operator_call(bContext *C, } } else { - wmOperatorType *ot = WM_operatortype_find(event->keymap_idname, 0); + wmOperatorType *ot = WM_operatortype_find(kmi_idname, 0); if (ot && wm_operator_check_locked_interface(C, ot)) { bool use_last_properties = true; @@ -2636,10 +2407,8 @@ static int wm_handlers_do_keymap_with_keymap_handler( PRINT("%s: item matched '%s'\n", __func__, 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); + action |= wm_handler_operator_call( + C, handlers, &handler->head, event, kmi->ptr, kmi->idname); if (action & WM_HANDLER_BREAK) { /* not always_pass here, it denotes removed handler_base */ @@ -2693,13 +2462,11 @@ 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); + action |= wm_handler_operator_call( + C, handlers, &handler->head, event, kmi->ptr, kmi->idname); CTX_wm_gizmo_group_set(C, NULL); @@ -2990,7 +2757,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); + action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL, NULL); } } else { @@ -4099,91 +3866,6 @@ 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; -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -4421,22 +4103,6 @@ static void wm_eventemulation(wmEvent *event, bool test_only) } } -/* applies the global tablet pressure correction curve */ -float wm_pressure_curve(float 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) { @@ -5003,6 +4669,29 @@ 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 @@ -5024,96 +4713,12 @@ void WM_set_locked_interface(wmWindowManager *wm, bool lock) BKE_spacedata_draw_locks(lock); } -#ifdef WITH_INPUT_NDOF +/** \} */ /* -------------------------------------------------------------------- */ -/** \name NDOF Utility Functions +/** \name Event / Keymap Matching API * \{ */ -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; @@ -5141,10 +4746,10 @@ wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wm return NULL; } -static wmKeyMapItem *wm_kmi_from_event(bContext *C, - wmWindowManager *wm, - ListBase *handlers, - const wmEvent *event) +wmKeyMapItem *WM_event_match_keymap_item_from_handlers(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 */ @@ -5167,6 +4772,8 @@ static wmKeyMapItem *wm_kmi_from_event(bContext *C, return NULL; } +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Cursor Keymap Status * @@ -5379,7 +4986,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_kmi_from_event(C, wm, handlers[handler_index], &test_event); + kmi = WM_event_match_keymap_item_from_handlers(C, wm, handlers[handler_index], &test_event); if (kmi) { break; } @@ -5475,43 +5082,3 @@ 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); -} - -/** \} */ diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 4ec62ff6d62..a118347ad9c 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -720,6 +720,111 @@ void WM_operator_properties_free(PointerRNA *ptr) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Operator Last Properties API + * \{ */ + +#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 + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Default Operator Callbacks * \{ */ diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index e68d4902c66..e7b6d65a3f9 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -702,6 +702,8 @@ static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, boo /* happens after fileread */ wm_window_ensure_eventstate(win); + + WM_window_set_dpi(win); } /* add keymap handlers (1 handler for all keys in map!) */ @@ -2189,8 +2191,8 @@ void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect) } } - BLI_assert(screen_rect.xmin < screen_rect.xmax); - BLI_assert(screen_rect.ymin < screen_rect.ymax); + BLI_assert(BLI_rcti_is_valid(&screen_rect)); + *r_rect = screen_rect; } diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index c53ccda170a..31aa61facb5 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -148,6 +148,7 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file); void wm_event_do_refresh_wm_and_depsgraph(bContext *C); void wm_event_do_notifiers(bContext *C); +/* wm_event_query.c */ float wm_pressure_curve(float raw_pressure); /* wm_keymap.c */ |