From 44eb5ea3c69dcec37e2b687e479297af5303efc3 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Fri, 8 Sep 2023 05:14:35 +1000 Subject: Revert "Updated bgfx, bx and bimg to current upstream versions. (#11493)" This reverts commit 1c61ccfe840cdae7a9f92292946a45f3b47e2412. --- 3rdparty/bgfx/.github/workflows/main.yml | 3 + 3rdparty/bgfx/3rdparty/cgltf/cgltf.h | 312 +- 3rdparty/bgfx/3rdparty/cgltf/cgltf_write.h | 22 +- 3rdparty/bgfx/3rdparty/dear-imgui/imgui.cpp | 4540 ++++----- 3rdparty/bgfx/3rdparty/dear-imgui/imgui.h | 353 +- 3rdparty/bgfx/3rdparty/dear-imgui/imgui_demo.cpp | 657 +- 3rdparty/bgfx/3rdparty/dear-imgui/imgui_draw.cpp | 185 +- 3rdparty/bgfx/3rdparty/dear-imgui/imgui_internal.h | 459 +- 3rdparty/bgfx/3rdparty/dear-imgui/imgui_tables.cpp | 331 +- .../bgfx/3rdparty/dear-imgui/imgui_widgets.cpp | 771 +- .../3rdparty/dear-imgui/widgets/memory_editor.inl | 4 +- .../3rdparty/dear-imgui/widgets/range_slider.inl | 2 +- .../glslang/OGLCompilersDLL/InitializeDll.cpp | 128 + .../glslang/OGLCompilersDLL/InitializeDll.h | 8 +- .../bgfx/3rdparty/glslang/SPIRV/GLSL.ext.ARM.h | 35 - .../bgfx/3rdparty/glslang/SPIRV/GLSL.ext.EXT.h | 1 - .../bgfx/3rdparty/glslang/SPIRV/GLSL.ext.KHR.h | 2 - 3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.NV.h | 3 - .../bgfx/3rdparty/glslang/SPIRV/GLSL.std.450.h | 2 +- .../bgfx/3rdparty/glslang/SPIRV/GlslangToSpv.cpp | 1042 +- .../bgfx/3rdparty/glslang/SPIRV/GlslangToSpv.h | 4 +- 3rdparty/bgfx/3rdparty/glslang/SPIRV/Logger.cpp | 4 + 3rdparty/bgfx/3rdparty/glslang/SPIRV/Logger.h | 9 + .../glslang/SPIRV/NonSemanticDebugPrintf.h | 10 +- .../glslang/SPIRV/NonSemanticShaderDebugInfo100.h | 10 +- .../bgfx/3rdparty/glslang/SPIRV/SPVRemapper.cpp | 7 +- 3rdparty/bgfx/3rdparty/glslang/SPIRV/SPVRemapper.h | 28 + .../bgfx/3rdparty/glslang/SPIRV/SpvBuilder.cpp | 230 +- 3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.h | 31 +- .../bgfx/3rdparty/glslang/SPIRV/SpvPostProcess.cpp | 7 +- 3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvTools.cpp | 53 +- 3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvTools.h | 19 - .../bgfx/3rdparty/glslang/SPIRV/disassemble.cpp | 63 +- 3rdparty/bgfx/3rdparty/glslang/SPIRV/doc.cpp | 3020 +++--- 3rdparty/bgfx/3rdparty/glslang/SPIRV/doc.h | 7 +- 3rdparty/bgfx/3rdparty/glslang/SPIRV/hex_float.h | 13 + 3rdparty/bgfx/3rdparty/glslang/SPIRV/spirv.hpp | 250 +- 3rdparty/bgfx/3rdparty/glslang/SPIRV/spvIR.h | 4 +- .../3rdparty/glslang/StandAlone/ResourceLimits.cpp | 540 + .../3rdparty/glslang/StandAlone/StandAlone.cpp | 69 +- .../glslang/StandAlone/resource_limits_c.cpp | 70 + .../3rdparty/glslang/StandAlone/spirv-remap.cpp | 99 +- 3rdparty/bgfx/3rdparty/glslang/build_info.h | 6 +- .../glslang/CInterface/glslang_c_interface.cpp | 53 +- .../glslang/glslang/GenericCodeGen/Link.cpp | 2 +- .../3rdparty/glslang/glslang/HLSL/hlslAttributes.h | 1 - .../3rdparty/glslang/glslang/HLSL/hlslGrammar.cpp | 309 +- .../3rdparty/glslang/glslang/HLSL/hlslGrammar.h | 6 +- .../glslang/glslang/HLSL/hlslParseHelper.cpp | 17 +- .../glslang/glslang/HLSL/hlslParseHelper.h | 8 +- .../glslang/glslang/HLSL/hlslParseables.cpp | 4 +- .../glslang/glslang/HLSL/hlslScanContext.cpp | 160 - .../3rdparty/glslang/glslang/HLSL/hlslTokens.h | 80 - .../3rdparty/glslang/glslang/Include/BaseTypes.h | 26 +- .../bgfx/3rdparty/glslang/glslang/Include/Common.h | 20 +- .../glslang/glslang/Include/ConstantUnion.h | 36 + .../glslang/glslang/Include/InitializeGlobals.h | 2 +- .../3rdparty/glslang/glslang/Include/PoolAlloc.h | 8 +- .../3rdparty/glslang/glslang/Include/ShHandle.h | 16 +- .../glslang/glslang/Include/SpirvIntrinsics.h | 21 +- .../bgfx/3rdparty/glslang/glslang/Include/Types.h | 540 +- .../bgfx/3rdparty/glslang/glslang/Include/arrays.h | 29 +- .../glslang/glslang/Include/glslang_c_interface.h | 50 +- .../glslang/glslang/Include/intermediate.h | 141 +- .../glslang/MachineIndependent/Constant.cpp | 30 +- .../glslang/MachineIndependent/Initialize.cpp | 532 +- .../glslang/MachineIndependent/Intermediate.cpp | 102 +- .../MachineIndependent/ParseContextBase.cpp | 20 +- .../glslang/MachineIndependent/ParseHelper.cpp | 814 +- .../glslang/MachineIndependent/ParseHelper.h | 29 +- .../glslang/MachineIndependent/PoolAlloc.cpp | 38 +- .../glslang/glslang/MachineIndependent/Scan.cpp | 56 +- .../glslang/MachineIndependent/ShaderLang.cpp | 118 +- .../glslang/MachineIndependent/SpirvIntrinsics.cpp | 74 +- .../glslang/MachineIndependent/SymbolTable.cpp | 17 +- .../glslang/MachineIndependent/SymbolTable.h | 49 +- .../glslang/MachineIndependent/Versions.cpp | 76 +- .../glslang/glslang/MachineIndependent/Versions.h | 9 - .../glslang/MachineIndependent/attribute.cpp | 4 + .../glslang/glslang/MachineIndependent/glslang.m4 | 4422 ++++++++ .../glslang/glslang/MachineIndependent/glslang.y | 227 +- .../glslang/MachineIndependent/glslang_tab.cpp | 10115 +++++++++---------- .../glslang/MachineIndependent/glslang_tab.cpp.h | 603 +- .../glslang/MachineIndependent/intermOut.cpp | 67 +- .../glslang/MachineIndependent/iomapper.cpp | 37 +- .../glslang/glslang/MachineIndependent/iomapper.h | 6 +- .../glslang/glslang/MachineIndependent/limits.cpp | 2 + .../glslang/MachineIndependent/linkValidate.cpp | 153 +- .../glslang/MachineIndependent/localintermediate.h | 143 +- .../glslang/MachineIndependent/parseConst.cpp | 2 +- .../glslang/MachineIndependent/parseVersions.h | 73 +- .../glslang/MachineIndependent/preprocessor/Pp.cpp | 24 +- .../MachineIndependent/preprocessor/PpContext.cpp | 2 +- .../MachineIndependent/preprocessor/PpContext.h | 23 +- .../MachineIndependent/preprocessor/PpScanner.cpp | 119 +- .../MachineIndependent/preprocessor/PpTokens.cpp | 11 +- .../MachineIndependent/propagateNoContraction.cpp | 8 +- .../glslang/MachineIndependent/reflection.cpp | 6 +- .../glslang/MachineIndependent/reflection.h | 4 + .../glslang/glslang/OSDependent/Unix/ossource.cpp | 70 + .../glslang/OSDependent/Windows/ossource.cpp | 60 +- .../glslang/glslang/OSDependent/osinclude.h | 11 + .../3rdparty/glslang/glslang/Public/ShaderLang.h | 9 + .../glslang/ResourceLimits/ResourceLimits.cpp | 542 - .../glslang/ResourceLimits/resource_limits_c.cpp | 70 - .../bgfx/3rdparty/glslang/glslang/updateGrammar | 15 +- 3rdparty/bgfx/3rdparty/glslang/hlsl/stub.cpp | 41 + 3rdparty/bgfx/3rdparty/khronos/EGL/egl.h | 85 +- 3rdparty/bgfx/3rdparty/khronos/EGL/eglext.h | 203 +- 3rdparty/bgfx/3rdparty/khronos/EGL/eglplatform.h | 55 +- 3rdparty/bgfx/3rdparty/khronos/GLES2/gl2.h | 29 +- 3rdparty/bgfx/3rdparty/khronos/GLES2/gl2ext.h | 398 +- 3rdparty/bgfx/3rdparty/khronos/GLES2/gl2platform.h | 15 +- 3rdparty/bgfx/3rdparty/khronos/GLES3/gl3.h | 37 +- 3rdparty/bgfx/3rdparty/khronos/GLES3/gl31.h | 39 +- 3rdparty/bgfx/3rdparty/khronos/GLES3/gl32.h | 39 +- 3rdparty/bgfx/3rdparty/khronos/GLES3/gl3ext.h | 24 + 3rdparty/bgfx/3rdparty/khronos/GLES3/gl3platform.h | 15 +- 3rdparty/bgfx/3rdparty/khronos/KHR/khrplatform.h | 37 +- .../bgfx/3rdparty/khronos/gl/GRemedyGLExtensions.h | 67 + 3rdparty/bgfx/3rdparty/khronos/gl/glcorearb.h | 219 +- 3rdparty/bgfx/3rdparty/khronos/gl/glext.h | 386 +- 3rdparty/bgfx/3rdparty/khronos/glx/glxext.h | 190 +- .../bgfx/3rdparty/khronos/vulkan-local/vk_icd.h | 26 +- .../bgfx/3rdparty/khronos/vulkan-local/vk_layer.h | 17 +- .../3rdparty/khronos/vulkan-local/vk_platform.h | 2 +- .../khronos/vulkan-local/vk_sdk_platform.h | 24 +- .../vk_video/vulkan_video_codec_h264std.h | 310 - .../vk_video/vulkan_video_codec_h264std_decode.h | 75 - .../vk_video/vulkan_video_codec_h264std_encode.h | 132 - .../vk_video/vulkan_video_codec_h265std.h | 443 - .../vk_video/vulkan_video_codec_h265std_decode.h | 65 - .../vk_video/vulkan_video_codec_h265std_encode.h | 146 - .../vk_video/vulkan_video_codecs_common.h | 31 - .../bgfx/3rdparty/khronos/vulkan-local/vulkan.h | 10 +- .../3rdparty/khronos/vulkan-local/vulkan_android.h | 2 +- .../3rdparty/khronos/vulkan-local/vulkan_beta.h | 1074 +- .../3rdparty/khronos/vulkan-local/vulkan_core.h | 1346 +-- .../khronos/vulkan-local/vulkan_directfb.h | 2 +- .../3rdparty/khronos/vulkan-local/vulkan_fuchsia.h | 2 +- .../3rdparty/khronos/vulkan-local/vulkan_ggp.h | 2 +- .../3rdparty/khronos/vulkan-local/vulkan_ios.h | 2 +- .../3rdparty/khronos/vulkan-local/vulkan_macos.h | 2 +- .../3rdparty/khronos/vulkan-local/vulkan_metal.h | 2 +- .../3rdparty/khronos/vulkan-local/vulkan_screen.h | 54 +- .../bgfx/3rdparty/khronos/vulkan-local/vulkan_vi.h | 2 +- .../3rdparty/khronos/vulkan-local/vulkan_wayland.h | 2 +- .../3rdparty/khronos/vulkan-local/vulkan_win32.h | 20 +- .../3rdparty/khronos/vulkan-local/vulkan_xcb.h | 2 +- .../3rdparty/khronos/vulkan-local/vulkan_xlib.h | 2 +- .../khronos/vulkan-local/vulkan_xlib_xrandr.h | 2 +- 3rdparty/bgfx/3rdparty/khronos/wgl/wgl.h | 936 -- 3rdparty/bgfx/3rdparty/khronos/wgl/wglext.h | 82 +- 3rdparty/bgfx/3rdparty/meshoptimizer/LICENSE.md | 2 +- .../3rdparty/meshoptimizer/src/indexgenerator.cpp | 39 +- .../3rdparty/meshoptimizer/src/meshoptimizer.h | 55 +- .../bgfx/3rdparty/meshoptimizer/src/simplifier.cpp | 393 +- .../3rdparty/meshoptimizer/src/vcacheoptimizer.cpp | 21 +- .../3rdparty/meshoptimizer/src/vertexcodec.cpp | 31 +- .../3rdparty/meshoptimizer/src/vertexfilter.cpp | 105 +- 3rdparty/bgfx/3rdparty/spirv-cross/main.cpp | 23 +- .../bgfx/3rdparty/spirv-cross/spirv_common.hpp | 8 +- 3rdparty/bgfx/3rdparty/spirv-cross/spirv_cross.cpp | 131 +- 3rdparty/bgfx/3rdparty/spirv-cross/spirv_cross.hpp | 6 +- .../bgfx/3rdparty/spirv-cross/spirv_cross_c.cpp | 93 - 3rdparty/bgfx/3rdparty/spirv-cross/spirv_cross_c.h | 22 +- .../spirv-cross/spirv_cross_containers.hpp | 3 +- .../3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp | 7 - 3rdparty/bgfx/3rdparty/spirv-cross/spirv_glsl.cpp | 1457 +-- 3rdparty/bgfx/3rdparty/spirv-cross/spirv_glsl.hpp | 65 +- 3rdparty/bgfx/3rdparty/spirv-cross/spirv_hlsl.cpp | 154 +- 3rdparty/bgfx/3rdparty/spirv-cross/spirv_hlsl.hpp | 11 +- 3rdparty/bgfx/3rdparty/spirv-cross/spirv_msl.cpp | 483 +- 3rdparty/bgfx/3rdparty/spirv-cross/spirv_msl.hpp | 31 +- .../bgfx/3rdparty/spirv-cross/spirv_parser.cpp | 2 - .../bgfx/3rdparty/spirv-cross/spirv_reflect.cpp | 2 +- .../spirv-headers/include/spirv/1.0/spirv.hpp11 | 1002 -- .../spirv-headers/include/spirv/1.1/spirv.hpp11 | 1024 -- .../spirv-headers/include/spirv/1.2/spirv.hpp11 | 1030 -- .../spirv-headers/include/spirv/spir-v.xml | 21 +- .../spirv/unified1/NonSemanticClspvReflection.h | 14 +- .../include/spirv/unified1/NonSemanticDebugBreak.h | 50 - ...xtinst.nonsemantic.clspvreflection.grammar.json | 68 +- .../extinst.nonsemantic.debugbreak.grammar.json | 9 - .../include/spirv/unified1/spirv.core.grammar.json | 1145 +-- .../spirv-headers/include/spirv/unified1/spirv.h | 183 - .../include/spirv/unified1/spirv.hpp11 | 2805 ----- .../include/spirv/unified1/spirv.json | 145 +- .../include/generated/build-version.inc | 2 +- .../include/generated/core.insts-unified1.inc | 1552 ++- .../include/generated/enum_string_mapping.inc | 474 +- .../include/generated/extension_enum.inc | 12 - .../spirv-tools/include/generated/generators.inc | 8 +- .../include/generated/glsl.std.450.insts.inc | 4 +- .../nonsemantic.clspvreflection.insts.inc | 9 +- .../include/generated/operand.kinds-unified1.inc | 390 +- .../spirv-tools/include/spirv-tools/instrument.hpp | 113 +- .../spirv-tools/include/spirv-tools/libspirv.h | 80 - .../spirv-tools/include/spirv-tools/libspirv.hpp | 22 - .../spirv-tools/include/spirv-tools/optimizer.hpp | 103 +- .../spirv-tools/source/assembly_grammar.cpp | 23 +- .../3rdparty/spirv-tools/source/assembly_grammar.h | 9 +- .../bgfx/3rdparty/spirv-tools/source/binary.cpp | 60 +- .../bgfx/3rdparty/spirv-tools/source/diff/diff.cpp | 506 +- .../3rdparty/spirv-tools/source/disassemble.cpp | 13 +- .../bgfx/3rdparty/spirv-tools/source/enum_set.h | 527 +- .../spirv-tools/source/enum_string_mapping.h | 2 +- .../3rdparty/spirv-tools/source/extensions.cpp | 9 +- .../bgfx/3rdparty/spirv-tools/source/extensions.h | 3 +- .../bgfx/3rdparty/spirv-tools/source/instruction.h | 2 +- .../source/latest_version_spirv_header.h | 2 +- .../bgfx/3rdparty/spirv-tools/source/libspirv.cpp | 34 - .../3rdparty/spirv-tools/source/link/linker.cpp | 57 +- .../source/lint/divergence_analysis.cpp | 43 +- .../source/lint/lint_divergent_derivatives.cpp | 46 +- .../3rdparty/spirv-tools/source/lint/linter.cpp | 1 + .../3rdparty/spirv-tools/source/name_mapper.cpp | 58 +- .../bgfx/3rdparty/spirv-tools/source/opcode.cpp | 773 +- 3rdparty/bgfx/3rdparty/spirv-tools/source/opcode.h | 65 +- .../bgfx/3rdparty/spirv-tools/source/operand.cpp | 67 +- .../bgfx/3rdparty/spirv-tools/source/operand.h | 2 +- .../source/opt/aggressive_dead_code_elim_pass.cpp | 233 +- .../source/opt/aggressive_dead_code_elim_pass.h | 13 +- .../spirv-tools/source/opt/amd_ext_to_khr.cpp | 234 +- .../source/opt/analyze_live_input_pass.cpp | 45 - .../source/opt/analyze_live_input_pass.h | 57 - .../spirv-tools/source/opt/basic_block.cpp | 47 +- .../3rdparty/spirv-tools/source/opt/basic_block.h | 2 +- .../spirv-tools/source/opt/block_merge_pass.cpp | 3 + .../spirv-tools/source/opt/block_merge_util.cpp | 36 +- .../3rdparty/spirv-tools/source/opt/ccp_pass.cpp | 16 +- .../bgfx/3rdparty/spirv-tools/source/opt/cfg.cpp | 12 +- .../spirv-tools/source/opt/cfg_cleanup_pass.cpp | 4 + .../3rdparty/spirv-tools/source/opt/code_sink.cpp | 87 +- .../source/opt/combine_access_chains.cpp | 54 +- .../spirv-tools/source/opt/combine_access_chains.h | 4 +- .../spirv-tools/source/opt/const_folding_rules.cpp | 472 +- .../spirv-tools/source/opt/const_folding_rules.h | 10 +- .../3rdparty/spirv-tools/source/opt/constants.cpp | 104 +- .../3rdparty/spirv-tools/source/opt/constants.h | 21 +- .../spirv-tools/source/opt/control_dependence.cpp | 7 +- .../source/opt/convert_to_half_pass.cpp | 244 +- .../spirv-tools/source/opt/convert_to_half_pass.h | 24 +- .../source/opt/convert_to_sampled_image_pass.cpp | 64 +- .../source/opt/convert_to_sampled_image_pass.h | 4 +- .../spirv-tools/source/opt/copy_prop_arrays.cpp | 108 +- .../spirv-tools/source/opt/copy_prop_arrays.h | 4 +- .../3rdparty/spirv-tools/source/opt/dataflow.cpp | 3 +- .../source/opt/dead_branch_elim_pass.cpp | 57 +- .../source/opt/dead_insert_elim_pass.cpp | 57 +- .../source/opt/dead_variable_elimination.cpp | 15 +- .../spirv-tools/source/opt/debug_info_manager.cpp | 88 +- .../spirv-tools/source/opt/decoration_manager.cpp | 103 +- .../spirv-tools/source/opt/decoration_manager.h | 25 +- .../3rdparty/spirv-tools/source/opt/desc_sroa.cpp | 49 +- .../spirv-tools/source/opt/desc_sroa_util.cpp | 31 +- .../spirv-tools/source/opt/dominator_analysis.cpp | 2 +- .../spirv-tools/source/opt/dominator_tree.cpp | 9 +- .../source/opt/eliminate_dead_constant_pass.cpp | 9 +- .../source/opt/eliminate_dead_functions_util.cpp | 8 +- .../opt/eliminate_dead_input_components_pass.cpp | 189 + .../opt/eliminate_dead_input_components_pass.h | 65 + .../opt/eliminate_dead_io_components_pass.cpp | 256 - .../source/opt/eliminate_dead_io_components_pass.h | 75 - .../source/opt/eliminate_dead_members_pass.cpp | 236 +- .../opt/eliminate_dead_output_stores_pass.cpp | 237 - .../source/opt/eliminate_dead_output_stores_pass.h | 81 - .../spirv-tools/source/opt/feature_manager.cpp | 34 +- .../spirv-tools/source/opt/feature_manager.h | 49 +- .../source/opt/fix_func_call_arguments.cpp | 9 +- .../spirv-tools/source/opt/fix_storage_class.cpp | 110 +- .../spirv-tools/source/opt/fix_storage_class.h | 8 +- .../source/opt/flatten_decoration_pass.cpp | 18 +- .../bgfx/3rdparty/spirv-tools/source/opt/fold.cpp | 281 +- .../bgfx/3rdparty/spirv-tools/source/opt/fold.h | 22 +- .../fold_spec_constant_op_and_composite_pass.cpp | 37 +- .../spirv-tools/source/opt/folding_rules.cpp | 687 +- .../spirv-tools/source/opt/folding_rules.h | 10 +- .../source/opt/freeze_spec_constant_value_pass.cpp | 18 +- .../3rdparty/spirv-tools/source/opt/function.cpp | 4 +- .../3rdparty/spirv-tools/source/opt/function.h | 2 +- .../source/opt/graphics_robust_access_pass.cpp | 100 +- .../source/opt/graphics_robust_access_pass.h | 2 +- .../spirv-tools/source/opt/if_conversion.cpp | 33 +- .../spirv-tools/source/opt/inline_opaque_pass.cpp | 16 +- .../spirv-tools/source/opt/inline_pass.cpp | 82 +- .../3rdparty/spirv-tools/source/opt/inline_pass.h | 2 +- .../source/opt/inst_bindless_check_pass.cpp | 1008 +- .../source/opt/inst_bindless_check_pass.h | 132 +- .../source/opt/inst_buff_addr_check_pass.cpp | 251 +- .../source/opt/inst_buff_addr_check_pass.h | 7 +- .../source/opt/inst_debug_printf_pass.cpp | 52 +- .../spirv-tools/source/opt/instruction.cpp | 490 +- .../3rdparty/spirv-tools/source/opt/instruction.h | 44 +- .../spirv-tools/source/opt/instrument_pass.cpp | 731 +- .../spirv-tools/source/opt/instrument_pass.h | 76 +- .../spirv-tools/source/opt/interface_var_sroa.cpp | 178 +- .../spirv-tools/source/opt/interface_var_sroa.h | 12 +- .../spirv-tools/source/opt/interp_fixup_pass.cpp | 12 +- .../3rdparty/spirv-tools/source/opt/ir_builder.h | 103 +- .../3rdparty/spirv-tools/source/opt/ir_context.cpp | 665 +- .../3rdparty/spirv-tools/source/opt/ir_context.h | 138 +- .../3rdparty/spirv-tools/source/opt/ir_loader.cpp | 54 +- .../3rdparty/spirv-tools/source/opt/licm_pass.cpp | 7 +- .../3rdparty/spirv-tools/source/opt/liveness.cpp | 332 - .../3rdparty/spirv-tools/source/opt/liveness.h | 99 - .../source/opt/local_access_chain_convert_pass.cpp | 143 +- .../source/opt/local_access_chain_convert_pass.h | 2 +- .../source/opt/local_single_block_elim_pass.cpp | 143 +- .../source/opt/local_single_store_elim_pass.cpp | 158 +- .../spirv-tools/source/opt/loop_dependence.cpp | 13 +- .../source/opt/loop_dependence_helpers.cpp | 40 +- .../spirv-tools/source/opt/loop_descriptor.cpp | 112 +- .../spirv-tools/source/opt/loop_descriptor.h | 16 +- .../spirv-tools/source/opt/loop_fission.cpp | 32 +- .../spirv-tools/source/opt/loop_fusion.cpp | 37 +- .../spirv-tools/source/opt/loop_fusion_pass.cpp | 1 + .../spirv-tools/source/opt/loop_peeling.cpp | 89 +- .../spirv-tools/source/opt/loop_unroller.cpp | 24 +- .../spirv-tools/source/opt/loop_unswitch_pass.cpp | 36 +- .../3rdparty/spirv-tools/source/opt/loop_utils.cpp | 21 +- .../3rdparty/spirv-tools/source/opt/mem_pass.cpp | 109 +- .../3rdparty/spirv-tools/source/opt/mem_pass.h | 6 +- .../spirv-tools/source/opt/merge_return_pass.cpp | 113 +- .../3rdparty/spirv-tools/source/opt/module.cpp | 23 +- .../bgfx/3rdparty/spirv-tools/source/opt/module.h | 5 +- .../3rdparty/spirv-tools/source/opt/optimizer.cpp | 211 +- .../bgfx/3rdparty/spirv-tools/source/opt/pass.cpp | 13 +- .../bgfx/3rdparty/spirv-tools/source/opt/passes.h | 5 +- .../source/opt/private_to_local_pass.cpp | 41 +- .../3rdparty/spirv-tools/source/opt/propagator.cpp | 4 +- .../3rdparty/spirv-tools/source/opt/propagator.h | 4 +- .../spirv-tools/source/opt/reduce_load_size.cpp | 33 +- .../bgfx/3rdparty/spirv-tools/source/opt/reflect.h | 52 +- .../spirv-tools/source/opt/register_pressure.cpp | 23 +- .../source/opt/relax_float_ops_pass.cpp | 140 +- .../spirv-tools/source/opt/relax_float_ops_pass.h | 12 +- .../source/opt/remove_dontinline_pass.cpp | 5 +- .../source/opt/remove_duplicates_pass.cpp | 12 +- .../opt/remove_unused_interface_variables_pass.cpp | 13 +- .../opt/remove_unused_interface_variables_pass.h | 7 +- .../replace_desc_array_access_using_var_index.cpp | 49 +- .../spirv-tools/source/opt/replace_invalid_opc.cpp | 82 +- .../spirv-tools/source/opt/replace_invalid_opc.h | 8 +- .../spirv-tools/source/opt/scalar_analysis.cpp | 31 +- .../source/opt/scalar_analysis_simplification.cpp | 5 +- .../source/opt/scalar_replacement_pass.cpp | 378 +- .../source/opt/scalar_replacement_pass.h | 27 +- .../opt/set_spec_constant_default_value_pass.cpp | 37 +- .../spirv-tools/source/opt/simplification_pass.cpp | 17 +- .../source/opt/spread_volatile_semantics.cpp | 100 +- .../source/opt/spread_volatile_semantics.h | 5 +- .../spirv-tools/source/opt/ssa_rewrite_pass.cpp | 18 +- .../source/opt/strength_reduction_pass.cpp | 24 +- .../source/opt/strip_debug_info_pass.cpp | 7 +- .../source/opt/strip_nonsemantic_info_pass.cpp | 27 +- .../spirv-tools/source/opt/struct_cfg_analysis.cpp | 17 +- .../source/opt/trim_capabilities_pass.cpp | 320 - .../source/opt/trim_capabilities_pass.h | 151 - .../spirv-tools/source/opt/type_manager.cpp | 194 +- .../3rdparty/spirv-tools/source/opt/type_manager.h | 32 +- .../bgfx/3rdparty/spirv-tools/source/opt/types.cpp | 67 +- .../bgfx/3rdparty/spirv-tools/source/opt/types.h | 89 +- .../spirv-tools/source/opt/unify_const_pass.cpp | 20 +- .../source/opt/upgrade_memory_model.cpp | 210 +- .../spirv-tools/source/opt/upgrade_memory_model.h | 8 +- .../spirv-tools/source/opt/value_number_table.cpp | 12 +- .../3rdparty/spirv-tools/source/opt/vector_dce.cpp | 20 +- .../spirv-tools/source/opt/workaround1209.cpp | 4 +- .../spirv-tools/source/opt/wrap_opkill.cpp | 28 +- .../3rdparty/spirv-tools/source/opt/wrap_opkill.h | 2 +- .../3rdparty/spirv-tools/source/parsed_operand.cpp | 1 - ...imple_conditional_branch_opportunity_finder.cpp | 4 +- .../reduce/merge_blocks_reduction_opportunity.cpp | 2 +- ...erand_to_const_reduction_opportunity_finder.cpp | 2 +- ...erand_to_undef_reduction_opportunity_finder.cpp | 6 +- .../spirv-tools/source/reduce/reduction_util.cpp | 20 +- ...move_selection_reduction_opportunity_finder.cpp | 4 +- .../remove_struct_member_reduction_opportunity.cpp | 28 +- ...ed_instruction_reduction_opportunity_finder.cpp | 28 +- ..._struct_member_reduction_opportunity_finder.cpp | 26 +- ...itional_branch_to_branch_opportunity_finder.cpp | 6 +- ...onal_branch_to_branch_reduction_opportunity.cpp | 5 +- ...ed_construct_to_block_reduction_opportunity.cpp | 2 +- ...red_loop_to_selection_reduction_opportunity.cpp | 23 +- .../spirv-tools/source/spirv_target_env.cpp | 1 - 3rdparty/bgfx/3rdparty/spirv-tools/source/table.h | 8 +- 3rdparty/bgfx/3rdparty/spirv-tools/source/text.cpp | 34 +- .../3rdparty/spirv-tools/source/text_handler.cpp | 4 +- .../3rdparty/spirv-tools/source/util/hex_float.h | 75 +- .../spirv-tools/source/util/small_vector.h | 16 +- .../spirv-tools/source/val/basic_block.cpp | 1 + .../3rdparty/spirv-tools/source/val/construct.cpp | 25 +- .../3rdparty/spirv-tools/source/val/decoration.h | 12 +- .../3rdparty/spirv-tools/source/val/function.cpp | 9 +- .../3rdparty/spirv-tools/source/val/function.h | 16 +- .../3rdparty/spirv-tools/source/val/instruction.h | 6 +- .../3rdparty/spirv-tools/source/val/validate.cpp | 48 +- .../3rdparty/spirv-tools/source/val/validate.h | 12 +- .../spirv-tools/source/val/validate_adjacency.cpp | 36 +- .../spirv-tools/source/val/validate_annotation.cpp | 300 +- .../source/val/validate_arithmetics.cpp | 225 +- .../spirv-tools/source/val/validate_atomics.cpp | 201 +- .../spirv-tools/source/val/validate_barriers.cpp | 29 +- .../spirv-tools/source/val/validate_bitwise.cpp | 36 +- .../spirv-tools/source/val/validate_builtins.cpp | 1090 +- .../spirv-tools/source/val/validate_capability.cpp | 282 +- .../spirv-tools/source/val/validate_cfg.cpp | 153 +- .../spirv-tools/source/val/validate_composites.cpp | 114 +- .../spirv-tools/source/val/validate_constants.cpp | 126 +- .../spirv-tools/source/val/validate_conversion.cpp | 128 +- .../spirv-tools/source/val/validate_debug.cpp | 12 +- .../source/val/validate_decorations.cpp | 586 +- .../source/val/validate_derivatives.cpp | 39 +- .../source/val/validate_execution_limitations.cpp | 4 +- .../spirv-tools/source/val/validate_extensions.cpp | 566 +- .../spirv-tools/source/val/validate_function.cpp | 106 +- .../spirv-tools/source/val/validate_id.cpp | 49 +- .../spirv-tools/source/val/validate_image.cpp | 758 +- .../source/val/validate_instruction.cpp | 112 +- .../spirv-tools/source/val/validate_interfaces.cpp | 155 +- .../spirv-tools/source/val/validate_layout.cpp | 30 +- .../spirv-tools/source/val/validate_literals.cpp | 5 +- .../spirv-tools/source/val/validate_logicals.cpp | 110 +- .../spirv-tools/source/val/validate_memory.cpp | 790 +- .../source/val/validate_memory_semantics.cpp | 125 +- .../source/val/validate_mesh_shading.cpp | 22 +- .../spirv-tools/source/val/validate_misc.cpp | 41 +- .../source/val/validate_mode_setting.cpp | 455 +- .../source/val/validate_non_uniform.cpp | 366 +- .../spirv-tools/source/val/validate_primitives.cpp | 22 +- .../spirv-tools/source/val/validate_ray_query.cpp | 73 +- .../source/val/validate_ray_tracing.cpp | 52 +- .../source/val/validate_ray_tracing_reorder.cpp | 625 -- .../spirv-tools/source/val/validate_scopes.cpp | 152 +- .../source/val/validate_small_type_uses.cpp | 16 +- .../spirv-tools/source/val/validate_type.cpp | 152 +- .../spirv-tools/source/val/validation_state.cpp | 613 +- .../spirv-tools/source/val/validation_state.h | 68 +- 3rdparty/bgfx/LICENSE | 2 +- 3rdparty/bgfx/README.mame | 4 - 3rdparty/bgfx/README.md | 311 +- 3rdparty/bgfx/bindings/bf/bgfx.bf | 16 +- 3rdparty/bgfx/bindings/cs/bgfx.cs | 16 +- 3rdparty/bgfx/bindings/cs/bgfx_dllname.cs | 2 +- 3rdparty/bgfx/bindings/d/fakeenum.d | 79 - 3rdparty/bgfx/bindings/d/funcs.d | 4569 +++++++++ 3rdparty/bgfx/bindings/d/package.d | 3573 ------- 3rdparty/bgfx/bindings/d/types.d | 1140 +++ 3rdparty/bgfx/bindings/zig/bgfx.zig | 16 +- 3rdparty/bgfx/docs/build.rst | 4 +- 3rdparty/bgfx/docs/internals.rst | 2 +- 3rdparty/bgfx/docs/license.rst | 2 +- 3rdparty/bgfx/docs/overview.rst | 26 +- 3rdparty/bgfx/docs/tools.rst | 43 - .../bgfx/examples/00-helloworld/helloworld.cpp | 11 +- 3rdparty/bgfx/examples/01-cubes/cubes.cpp | 3 +- 3rdparty/bgfx/examples/01-cubes/fs_cubes.sc | 2 +- 3rdparty/bgfx/examples/01-cubes/makefile | 2 +- 3rdparty/bgfx/examples/01-cubes/vs_cubes.sc | 2 +- .../bgfx/examples/02-metaballs/fs_metaballs.sc | 2 +- 3rdparty/bgfx/examples/02-metaballs/makefile | 2 +- 3rdparty/bgfx/examples/02-metaballs/metaballs.cpp | 3 +- .../bgfx/examples/02-metaballs/vs_metaballs.sc | 2 +- .../bgfx/examples/03-raymarch/fs_raymarching.sc | 2 +- 3rdparty/bgfx/examples/03-raymarch/makefile | 2 +- 3rdparty/bgfx/examples/03-raymarch/raymarch.cpp | 3 +- .../bgfx/examples/03-raymarch/vs_raymarching.sc | 2 +- 3rdparty/bgfx/examples/04-mesh/fs_mesh.sc | 2 +- 3rdparty/bgfx/examples/04-mesh/makefile | 2 +- 3rdparty/bgfx/examples/04-mesh/mesh.cpp | 3 +- 3rdparty/bgfx/examples/04-mesh/vs_mesh.sc | 2 +- .../bgfx/examples/05-instancing/fs_instancing.sc | 2 +- .../bgfx/examples/05-instancing/instancing.cpp | 3 +- 3rdparty/bgfx/examples/05-instancing/makefile | 2 +- .../bgfx/examples/05-instancing/vs_instancing.sc | 2 +- 3rdparty/bgfx/examples/06-bump/bump.cpp | 3 +- 3rdparty/bgfx/examples/06-bump/fs_bump.sc | 2 +- 3rdparty/bgfx/examples/06-bump/makefile | 2 +- 3rdparty/bgfx/examples/06-bump/vs_bump.sc | 2 +- .../bgfx/examples/06-bump/vs_bump_instanced.sc | 2 +- 3rdparty/bgfx/examples/07-callback/callback.cpp | 13 +- 3rdparty/bgfx/examples/07-callback/fs_callback.sc | 2 +- 3rdparty/bgfx/examples/07-callback/makefile | 2 +- 3rdparty/bgfx/examples/07-callback/vs_callback.sc | 2 +- 3rdparty/bgfx/examples/08-update/fs_update.sc | 2 +- 3rdparty/bgfx/examples/08-update/fs_update_3d.sc | 2 +- 3rdparty/bgfx/examples/08-update/fs_update_cmp.sc | 2 +- 3rdparty/bgfx/examples/08-update/makefile | 2 +- 3rdparty/bgfx/examples/08-update/update.cpp | 8 +- 3rdparty/bgfx/examples/08-update/vs_update.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/common.sh | 2 +- 3rdparty/bgfx/examples/09-hdr/fs_hdr_blur.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/fs_hdr_bright.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/fs_hdr_lum.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/fs_hdr_lumavg.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/fs_hdr_mesh.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/fs_hdr_skybox.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/fs_hdr_tonemap.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/hdr.cpp | 3 +- 3rdparty/bgfx/examples/09-hdr/makefile | 2 +- 3rdparty/bgfx/examples/09-hdr/vs_hdr_blur.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/vs_hdr_bright.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/vs_hdr_lum.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/vs_hdr_lumavg.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/vs_hdr_mesh.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/vs_hdr_skybox.sc | 2 +- 3rdparty/bgfx/examples/09-hdr/vs_hdr_tonemap.sc | 2 +- 3rdparty/bgfx/examples/10-font/font.cpp | 3 +- 3rdparty/bgfx/examples/11-fontsdf/fontsdf.cpp | 3 +- 3rdparty/bgfx/examples/12-lod/lod.cpp | 1 - 3rdparty/bgfx/examples/12-lod/makefile | 2 +- 3rdparty/bgfx/examples/13-stencil/makefile | 2 +- 3rdparty/bgfx/examples/13-stencil/stencil.cpp | 1 - 3rdparty/bgfx/examples/14-shadowvolumes/makefile | 2 +- .../examples/14-shadowvolumes/shadowvolumes.cpp | 1 - .../bgfx/examples/15-shadowmaps-simple/makefile | 2 +- .../15-shadowmaps-simple/shadowmaps_simple.cpp | 1 - 3rdparty/bgfx/examples/16-shadowmaps/makefile | 2 +- .../bgfx/examples/16-shadowmaps/shadowmaps.cpp | 1 - .../examples/16-shadowmaps/vs_shadowmaps_hblur.sc | 2 +- .../bgfx/examples/17-drawstress/drawstress.cpp | 3 +- .../bgfx/examples/17-drawstress/fs_drawstress.sc | 2 +- 3rdparty/bgfx/examples/17-drawstress/makefile | 2 +- .../bgfx/examples/17-drawstress/vs_drawstress.sc | 2 +- 3rdparty/bgfx/examples/18-ibl/ibl.cpp | 5 +- 3rdparty/bgfx/examples/18-ibl/makefile | 2 +- 3rdparty/bgfx/examples/19-oit/fs_oit.sc | 2 +- 3rdparty/bgfx/examples/19-oit/fs_oit_wb.sc | 2 +- 3rdparty/bgfx/examples/19-oit/fs_oit_wb_blit.sc | 2 +- .../bgfx/examples/19-oit/fs_oit_wb_separate.sc | 2 +- .../examples/19-oit/fs_oit_wb_separate_blit.sc | 2 +- 3rdparty/bgfx/examples/19-oit/makefile | 2 +- 3rdparty/bgfx/examples/19-oit/oit.cpp | 3 +- 3rdparty/bgfx/examples/19-oit/vs_oit.sc | 2 +- 3rdparty/bgfx/examples/19-oit/vs_oit_blit.sc | 2 +- 3rdparty/bgfx/examples/20-nanovg/nanovg.cpp | 3 +- 3rdparty/bgfx/examples/21-deferred/common.sh | 2 +- 3rdparty/bgfx/examples/21-deferred/deferred.cpp | 3 +- .../examples/21-deferred/fs_deferred_clear_uav.sc | 2 +- .../examples/21-deferred/fs_deferred_combine.sc | 2 +- .../examples/21-deferred/fs_deferred_combine_ta.sc | 2 +- .../bgfx/examples/21-deferred/fs_deferred_debug.sc | 2 +- .../examples/21-deferred/fs_deferred_debug_line.sc | 2 +- .../examples/21-deferred/fs_deferred_debug_ta.sc | 2 +- .../bgfx/examples/21-deferred/fs_deferred_geom.sc | 2 +- .../bgfx/examples/21-deferred/fs_deferred_light.sc | 2 +- .../examples/21-deferred/fs_deferred_light_ta.sc | 2 +- .../examples/21-deferred/fs_deferred_light_uav.sc | 2 +- 3rdparty/bgfx/examples/21-deferred/makefile | 2 +- .../examples/21-deferred/vs_deferred_combine.sc | 2 +- .../bgfx/examples/21-deferred/vs_deferred_debug.sc | 2 +- .../examples/21-deferred/vs_deferred_debug_line.sc | 2 +- .../bgfx/examples/21-deferred/vs_deferred_geom.sc | 2 +- .../bgfx/examples/21-deferred/vs_deferred_light.sc | 2 +- 3rdparty/bgfx/examples/22-windows/windows.cpp | 7 +- 3rdparty/bgfx/examples/23-vectordisplay/makefile | 2 +- 3rdparty/bgfx/examples/24-nbody/makefile | 2 +- 3rdparty/bgfx/examples/24-nbody/nbody.cpp | 1 - 3rdparty/bgfx/examples/25-c99/helloworld.c | 6 +- 3rdparty/bgfx/examples/26-occlusion/occlusion.cpp | 3 +- 3rdparty/bgfx/examples/27-terrain/makefile | 2 +- 3rdparty/bgfx/examples/27-terrain/terrain.cpp | 13 +- 3rdparty/bgfx/examples/28-wireframe/makefile | 2 +- 3rdparty/bgfx/examples/28-wireframe/wireframe.cpp | 9 +- 3rdparty/bgfx/examples/29-debugdraw/debugdraw.cpp | 9 +- 3rdparty/bgfx/examples/30-picking/fs_picking_id.sc | 2 +- .../bgfx/examples/30-picking/fs_picking_shaded.sc | 2 +- 3rdparty/bgfx/examples/30-picking/makefile | 2 +- 3rdparty/bgfx/examples/30-picking/picking.cpp | 1 - .../bgfx/examples/30-picking/vs_picking_shaded.sc | 2 +- 3rdparty/bgfx/examples/31-rsm/makefile | 2 +- .../bgfx/examples/31-rsm/reflectiveshadowmap.cpp | 1 - 3rdparty/bgfx/examples/32-particles/particles.cpp | 3 +- 3rdparty/bgfx/examples/33-pom/makefile | 2 +- 3rdparty/bgfx/examples/33-pom/pom.cpp | 3 +- 3rdparty/bgfx/examples/34-mvs/mvs.cpp | 3 +- 3rdparty/bgfx/examples/35-dynamic/dynamic.cpp | 3 +- 3rdparty/bgfx/examples/36-sky/makefile | 2 +- 3rdparty/bgfx/examples/36-sky/sky.cpp | 11 +- 3rdparty/bgfx/examples/36-sky/vs_sky_landscape.sc | 2 +- .../37-gpudrivenrendering/gpudrivenrendering.cpp | 5 +- .../bgfx/examples/37-gpudrivenrendering/makefile | 2 +- 3rdparty/bgfx/examples/38-bloom/bloom.cpp | 1 - .../bgfx/examples/38-bloom/fs_bloom_combine.sc | 2 +- 3rdparty/bgfx/examples/38-bloom/makefile | 2 +- .../bgfx/examples/38-bloom/vs_deferred_combine.sc | 2 +- 3rdparty/bgfx/examples/39-assao/assao.cpp | 1 - 3rdparty/bgfx/examples/39-assao/makefile | 2 +- 3rdparty/bgfx/examples/40-svt/fs_vt_mip.sc | 2 +- 3rdparty/bgfx/examples/40-svt/fs_vt_unlit.sc | 2 +- 3rdparty/bgfx/examples/40-svt/makefile | 2 +- 3rdparty/bgfx/examples/40-svt/svt.cpp | 1 - 3rdparty/bgfx/examples/40-svt/virtualtexture.sh | 2 +- 3rdparty/bgfx/examples/40-svt/vs_vt_generic.sc | 2 +- 3rdparty/bgfx/examples/40-svt/vt.cpp | 40 +- 3rdparty/bgfx/examples/41-tess/makefile | 2 +- 3rdparty/bgfx/examples/41-tess/tess.cpp | 1 - 3rdparty/bgfx/examples/42-bunnylod/bunnylod.cpp | 43 +- 3rdparty/bgfx/examples/42-bunnylod/fs_bunnylod.sc | 2 +- 3rdparty/bgfx/examples/42-bunnylod/makefile | 2 +- 3rdparty/bgfx/examples/42-bunnylod/vs_bunnylod.sc | 2 +- 3rdparty/bgfx/examples/43-denoise/denoise.cpp | 1 - .../bgfx/examples/44-sss/screen_space_shadows.cpp | 1 - 3rdparty/bgfx/examples/45-bokeh/bokeh.cpp | 1 - 3rdparty/bgfx/examples/46-fsr/makefile | 2 +- 3rdparty/bgfx/examples/47-pixelformats/makefile | 2 +- .../bgfx/examples/47-pixelformats/pixelformats.cpp | 43 +- .../bgfx/examples/48-drawindirect/drawindirect.cpp | 1 - 3rdparty/bgfx/examples/48-drawindirect/makefile | 2 +- 3rdparty/bgfx/examples/49-hextile/hextile.cpp | 1 - 3rdparty/bgfx/examples/49-hextile/makefile | 2 +- 3rdparty/bgfx/examples/common/aviwriter.h | 2 +- 3rdparty/bgfx/examples/common/bgfx_utils.cpp | 32 +- 3rdparty/bgfx/examples/common/bgfx_utils.h | 2 +- 3rdparty/bgfx/examples/common/camera.cpp | 8 +- 3rdparty/bgfx/examples/common/common.h | 2 +- 3rdparty/bgfx/examples/common/common.sh | 2 +- .../bgfx/examples/common/debugdraw/debugdraw.cpp | 48 +- .../bgfx/examples/common/debugdraw/debugdraw.h | 2 +- .../examples/common/debugdraw/fs_debugdraw_fill.sc | 2 +- .../common/debugdraw/fs_debugdraw_fill_lit.sc | 2 +- .../common/debugdraw/fs_debugdraw_fill_texture.sc | 2 +- .../common/debugdraw/fs_debugdraw_lines.sc | 2 +- .../common/debugdraw/fs_debugdraw_lines_stipple.sc | 2 +- 3rdparty/bgfx/examples/common/debugdraw/makefile | 2 +- .../examples/common/debugdraw/vs_debugdraw_fill.sc | 2 +- .../common/debugdraw/vs_debugdraw_fill_lit.sc | 2 +- .../common/debugdraw/vs_debugdraw_fill_lit_mesh.sc | 2 +- .../common/debugdraw/vs_debugdraw_fill_mesh.sc | 2 +- .../common/debugdraw/vs_debugdraw_fill_texture.sc | 2 +- .../common/debugdraw/vs_debugdraw_lines.sc | 2 +- .../common/debugdraw/vs_debugdraw_lines_stipple.sc | 2 +- 3rdparty/bgfx/examples/common/entry/cmd.cpp | 4 +- 3rdparty/bgfx/examples/common/entry/cmd.h | 2 +- 3rdparty/bgfx/examples/common/entry/dbg.h | 2 +- 3rdparty/bgfx/examples/common/entry/dialog.cpp | 2 +- 3rdparty/bgfx/examples/common/entry/dialog.h | 2 +- .../bgfx/examples/common/entry/dialog_darwin.mm | 2 +- 3rdparty/bgfx/examples/common/entry/entry.cpp | 23 +- 3rdparty/bgfx/examples/common/entry/entry.h | 6 +- .../bgfx/examples/common/entry/entry_android.cpp | 14 +- 3rdparty/bgfx/examples/common/entry/entry_glfw.cpp | 15 +- .../bgfx/examples/common/entry/entry_html5.cpp | 8 +- 3rdparty/bgfx/examples/common/entry/entry_ios.mm | 13 +- 3rdparty/bgfx/examples/common/entry/entry_noop.cpp | 8 +- 3rdparty/bgfx/examples/common/entry/entry_osx.mm | 8 +- 3rdparty/bgfx/examples/common/entry/entry_p.h | 4 +- 3rdparty/bgfx/examples/common/entry/entry_sdl.cpp | 67 +- .../bgfx/examples/common/entry/entry_windows.cpp | 8 +- 3rdparty/bgfx/examples/common/entry/entry_x11.cpp | 8 +- 3rdparty/bgfx/examples/common/entry/input.cpp | 4 +- 3rdparty/bgfx/examples/common/entry/input.h | 2 +- 3rdparty/bgfx/examples/common/example-glue.cpp | 2 +- 3rdparty/bgfx/examples/common/font/makefile | 2 +- 3rdparty/bgfx/examples/common/imgui/imgui.cpp | 6 +- 3rdparty/bgfx/examples/common/imgui/imgui.h | 2 +- 3rdparty/bgfx/examples/common/imgui/makefile | 2 +- 3rdparty/bgfx/examples/common/nanovg/fontstash.h | 2 +- 3rdparty/bgfx/examples/common/nanovg/makefile | 2 +- .../bgfx/examples/common/nanovg/nanovg_bgfx.cpp | 71 +- 3rdparty/bgfx/examples/common/nanovg/nanovg_bgfx.h | 10 +- 3rdparty/bgfx/examples/common/packrect.h | 2 +- 3rdparty/bgfx/examples/common/ps/fs_particle.sc | 2 +- 3rdparty/bgfx/examples/common/ps/makefile | 2 +- .../bgfx/examples/common/ps/particle_system.cpp | 22 +- 3rdparty/bgfx/examples/common/ps/particle_system.h | 2 +- 3rdparty/bgfx/examples/common/ps/vs_particle.sc | 2 +- 3rdparty/bgfx/examples/common/shaderlib.sh | 2 +- 3rdparty/bgfx/examples/makefile | 2 +- .../shaders/metal/fs_deferred_combine_ta.bin | Bin 1109 -> 1110 bytes .../runtime/shaders/metal/fs_deferred_debug_ta.bin | Bin 771 -> 772 bytes .../runtime/shaders/metal/fs_deferred_light_ta.bin | Bin 1584 -> 1585 bytes .../runtime/shaders/metal/vs_albedo_output.bin | Bin 1372 -> 1324 bytes .../runtime/shaders/metal/vs_bokeh_forward.bin | Bin 1443 -> 1395 bytes .../runtime/shaders/metal/vs_bokeh_screenquad.bin | Bin 749 -> 701 bytes .../examples/runtime/shaders/metal/vs_bump.bin | Bin 1864 -> 1816 bytes .../runtime/shaders/metal/vs_bump_instanced.bin | Bin 2038 -> 1990 bytes .../examples/runtime/shaders/metal/vs_bunnylod.bin | Bin 934 -> 886 bytes .../examples/runtime/shaders/metal/vs_callback.bin | Bin 921 -> 873 bytes .../examples/runtime/shaders/metal/vs_cubes.bin | Bin 733 -> 685 bytes .../runtime/shaders/metal/vs_deferred_combine.bin | Bin 745 -> 697 bytes .../runtime/shaders/metal/vs_deferred_debug.bin | Bin 745 -> 697 bytes .../shaders/metal/vs_deferred_debug_line.bin | Bin 733 -> 685 bytes .../runtime/shaders/metal/vs_deferred_geom.bin | Bin 1885 -> 1837 bytes .../runtime/shaders/metal/vs_deferred_light.bin | Bin 745 -> 697 bytes .../runtime/shaders/metal/vs_denoise_gbuffer.bin | Bin 1782 -> 1734 bytes .../shaders/metal/vs_denoise_screenquad.bin | Bin 749 -> 701 bytes .../runtime/shaders/metal/vs_fsr_forward.bin | Bin 1416 -> 1368 bytes .../runtime/shaders/metal/vs_fsr_screenquad.bin | Bin 749 -> 701 bytes .../runtime/shaders/metal/vs_fullscreen.bin | Bin 745 -> 697 bytes .../examples/runtime/shaders/metal/vs_hdr_blur.bin | Bin 1744 -> 1696 bytes .../runtime/shaders/metal/vs_hdr_bright.bin | Bin 745 -> 697 bytes .../examples/runtime/shaders/metal/vs_hdr_lum.bin | Bin 745 -> 697 bytes .../runtime/shaders/metal/vs_hdr_lumavg.bin | Bin 745 -> 697 bytes .../examples/runtime/shaders/metal/vs_hdr_mesh.bin | Bin 1106 -> 1058 bytes .../runtime/shaders/metal/vs_hdr_skybox.bin | Bin 745 -> 697 bytes .../runtime/shaders/metal/vs_hdr_tonemap.bin | Bin 1769 -> 1721 bytes .../examples/runtime/shaders/metal/vs_hextile.bin | Bin 984 -> 936 bytes .../examples/runtime/shaders/metal/vs_ibl_mesh.bin | Bin 1049 -> 1001 bytes .../runtime/shaders/metal/vs_ibl_skybox.bin | Bin 1073 -> 1025 bytes .../runtime/shaders/metal/vs_instancing.bin | Bin 998 -> 950 bytes .../examples/runtime/shaders/metal/vs_mesh.bin | Bin 1681 -> 1633 bytes .../bgfx/examples/runtime/shaders/metal/vs_oit.bin | Bin 912 -> 864 bytes .../examples/runtime/shaders/metal/vs_oit_blit.bin | Bin 745 -> 697 bytes .../examples/runtime/shaders/metal/vs_particle.bin | Bin 1081 -> 1033 bytes .../runtime/shaders/metal/vs_picking_shaded.bin | Bin 1347 -> 1299 bytes .../bgfx/examples/runtime/shaders/metal/vs_pom.bin | Bin 1726 -> 1678 bytes .../runtime/shaders/metal/vs_raymarching.bin | Bin 890 -> 842 bytes .../runtime/shaders/metal/vs_rsm_combine.bin | Bin 745 -> 697 bytes .../runtime/shaders/metal/vs_rsm_gbuffer.bin | Bin 878 -> 830 bytes .../runtime/shaders/metal/vs_rsm_lbuffer.bin | Bin 1848 -> 1800 bytes .../runtime/shaders/metal/vs_rsm_shadow.bin | Bin 861 -> 813 bytes .../runtime/shaders/metal/vs_shadowmaps_color.bin | Bin 588 -> 540 bytes .../shaders/metal/vs_shadowmaps_color_lighting.bin | Bin 1303 -> 1255 bytes .../metal/vs_shadowmaps_color_lighting_csm.bin | Bin 2123 -> 2075 bytes .../metal/vs_shadowmaps_color_lighting_linear.bin | Bin 1354 -> 1306 bytes .../vs_shadowmaps_color_lighting_linear_csm.bin | Bin 2327 -> 2279 bytes .../vs_shadowmaps_color_lighting_linear_omni.bin | Bin 2265 -> 2217 bytes .../metal/vs_shadowmaps_color_lighting_omni.bin | Bin 2061 -> 2013 bytes .../shaders/metal/vs_shadowmaps_color_texture.bin | Bin 745 -> 697 bytes .../runtime/shaders/metal/vs_shadowmaps_depth.bin | Bin 588 -> 540 bytes .../runtime/shaders/metal/vs_shadowmaps_hblur.bin | Bin 1844 -> 1796 bytes .../shaders/metal/vs_shadowmaps_packdepth.bin | Bin 711 -> 663 bytes .../metal/vs_shadowmaps_packdepth_linear.bin | Bin 721 -> 673 bytes .../shaders/metal/vs_shadowmaps_texture.bin | Bin 745 -> 697 bytes .../metal/vs_shadowmaps_texture_lighting.bin | Bin 1149 -> 1101 bytes .../shaders/metal/vs_shadowmaps_unpackdepth.bin | Bin 745 -> 697 bytes .../runtime/shaders/metal/vs_shadowmaps_vblur.bin | Bin 1844 -> 1796 bytes .../metal/vs_shadowvolume_color_lighting.bin | Bin 996 -> 948 bytes .../metal/vs_shadowvolume_color_texture.bin | Bin 745 -> 697 bytes .../shaders/metal/vs_shadowvolume_svback.bin | Bin 797 -> 749 bytes .../shaders/metal/vs_shadowvolume_svfront.bin | Bin 588 -> 540 bytes .../shaders/metal/vs_shadowvolume_svside.bin | Bin 1073 -> 1025 bytes .../shaders/metal/vs_shadowvolume_texture.bin | Bin 745 -> 697 bytes .../metal/vs_shadowvolume_texture_lighting.bin | Bin 1149 -> 1101 bytes .../bgfx/examples/runtime/shaders/metal/vs_sky.bin | Bin 2857 -> 2809 bytes .../runtime/shaders/metal/vs_sky_landscape.bin | Bin 999 -> 951 bytes .../examples/runtime/shaders/metal/vs_sms_mesh.bin | Bin 1278 -> 1230 bytes .../runtime/shaders/metal/vs_sms_shadow.bin | Bin 588 -> 540 bytes .../runtime/shaders/metal/vs_sms_shadow_pd.bin | Bin 711 -> 663 bytes .../runtime/shaders/metal/vs_sss_gbuffer.bin | Bin 1185 -> 1137 bytes .../runtime/shaders/metal/vs_sss_screenquad.bin | Bin 749 -> 701 bytes .../runtime/shaders/metal/vs_stencil_color.bin | Bin 588 -> 540 bytes .../shaders/metal/vs_stencil_color_lighting.bin | Bin 994 -> 946 bytes .../shaders/metal/vs_stencil_color_texture.bin | Bin 745 -> 697 bytes .../runtime/shaders/metal/vs_stencil_texture.bin | Bin 745 -> 697 bytes .../shaders/metal/vs_stencil_texture_lighting.bin | Bin 1149 -> 1101 bytes .../examples/runtime/shaders/metal/vs_terrain.bin | Bin 856 -> 808 bytes .../shaders/metal/vs_terrain_height_texture.bin | Bin 1221 -> 1173 bytes .../runtime/shaders/metal/vs_terrain_render.bin | Bin 2479 -> 2431 bytes .../examples/runtime/shaders/metal/vs_tree.bin | Bin 1280 -> 1232 bytes .../examples/runtime/shaders/metal/vs_update.bin | Bin 745 -> 697 bytes .../runtime/shaders/metal/vs_vectordisplay_fb.bin | Bin 890 -> 842 bytes .../runtime/shaders/metal/vs_vt_generic.bin | Bin 813 -> 765 bytes .../examples/runtime/shaders/metal/vs_wf_mesh.bin | Bin 1185 -> 1137 bytes .../runtime/shaders/metal/vs_wf_wireframe.bin | Bin 979 -> 931 bytes 3rdparty/bgfx/include/bgfx/bgfx.h | 54 +- 3rdparty/bgfx/include/bgfx/c99/bgfx.h | 23 +- 3rdparty/bgfx/include/bgfx/defines.h | 9 +- 3rdparty/bgfx/include/bgfx/embedded_shader.h | 2 +- 3rdparty/bgfx/include/bgfx/platform.h | 2 +- 3rdparty/bgfx/makefile | 2 +- 3rdparty/bgfx/scripts/bgfx-codegen.lua | 2 +- 3rdparty/bgfx/scripts/bgfx.idl | 34 +- 3rdparty/bgfx/scripts/bgfx.lua | 4 +- 3rdparty/bgfx/scripts/bindings-bf.lua | 4 +- 3rdparty/bgfx/scripts/bindings-cs.lua | 6 +- 3rdparty/bgfx/scripts/bindings-d.lua | 964 +- 3rdparty/bgfx/scripts/bindings-zig.lua | 4 +- 3rdparty/bgfx/scripts/example-common.lua | 2 +- 3rdparty/bgfx/scripts/genie.lua | 8 +- 3rdparty/bgfx/scripts/geometryc.lua | 2 +- 3rdparty/bgfx/scripts/geometryv.lua | 20 +- 3rdparty/bgfx/scripts/idl.lua | 1 - 3rdparty/bgfx/scripts/shader-embeded.mk | 18 +- 3rdparty/bgfx/scripts/shader.mk | 12 +- 3rdparty/bgfx/scripts/shaderc.lua | 50 +- 3rdparty/bgfx/scripts/temp.bgfx.h | 2 +- 3rdparty/bgfx/scripts/temp.bgfx.idl.inl | 2 +- 3rdparty/bgfx/scripts/temp.defines.h | 2 +- 3rdparty/bgfx/scripts/texturec.lua | 2 +- 3rdparty/bgfx/scripts/texturev.lua | 20 +- 3rdparty/bgfx/scripts/tools.mk | 2 +- 3rdparty/bgfx/src/amalgamated.cpp | 3 +- 3rdparty/bgfx/src/amalgamated.mm | 4 +- 3rdparty/bgfx/src/bgfx.cpp | 99 +- 3rdparty/bgfx/src/bgfx.idl.inl | 2 +- 3rdparty/bgfx/src/bgfx_compute.sh | 2 +- 3rdparty/bgfx/src/bgfx_p.h | 78 +- 3rdparty/bgfx/src/bgfx_shader.sh | 40 +- 3rdparty/bgfx/src/charset.h | 2 +- 3rdparty/bgfx/src/config.h | 7 +- 3rdparty/bgfx/src/debug_renderdoc.cpp | 2 +- 3rdparty/bgfx/src/debug_renderdoc.h | 2 +- 3rdparty/bgfx/src/dxgi.cpp | 201 +- 3rdparty/bgfx/src/dxgi.h | 4 +- 3rdparty/bgfx/src/emscripten.h | 2 +- 3rdparty/bgfx/src/fs_clear0.sc | 2 +- 3rdparty/bgfx/src/fs_clear1.sc | 2 +- 3rdparty/bgfx/src/fs_clear2.sc | 2 +- 3rdparty/bgfx/src/fs_clear3.sc | 2 +- 3rdparty/bgfx/src/fs_clear4.sc | 2 +- 3rdparty/bgfx/src/fs_clear5.sc | 2 +- 3rdparty/bgfx/src/fs_clear6.sc | 2 +- 3rdparty/bgfx/src/fs_clear7.sc | 2 +- 3rdparty/bgfx/src/fs_debugfont.sc | 2 +- 3rdparty/bgfx/src/glcontext_eagl.h | 2 +- 3rdparty/bgfx/src/glcontext_eagl.mm | 4 +- 3rdparty/bgfx/src/glcontext_egl.cpp | 226 +- 3rdparty/bgfx/src/glcontext_egl.h | 13 +- 3rdparty/bgfx/src/glcontext_glx.cpp | 393 + 3rdparty/bgfx/src/glcontext_glx.h | 58 + 3rdparty/bgfx/src/glcontext_html5.cpp | 10 +- 3rdparty/bgfx/src/glcontext_html5.h | 2 +- 3rdparty/bgfx/src/glcontext_nsgl.h | 2 +- 3rdparty/bgfx/src/glcontext_nsgl.mm | 4 +- 3rdparty/bgfx/src/glcontext_wgl.cpp | 4 +- 3rdparty/bgfx/src/glcontext_wgl.h | 2 +- 3rdparty/bgfx/src/glimports.h | 2 +- 3rdparty/bgfx/src/makefile | 2 +- 3rdparty/bgfx/src/nvapi.cpp | 2 +- 3rdparty/bgfx/src/nvapi.h | 2 +- 3rdparty/bgfx/src/renderer.h | 2 +- 3rdparty/bgfx/src/renderer_agc.cpp | 2 +- 3rdparty/bgfx/src/renderer_d3d.h | 2 +- 3rdparty/bgfx/src/renderer_d3d11.cpp | 37 +- 3rdparty/bgfx/src/renderer_d3d11.h | 2 +- 3rdparty/bgfx/src/renderer_d3d12.cpp | 55 +- 3rdparty/bgfx/src/renderer_d3d12.h | 2 +- 3rdparty/bgfx/src/renderer_d3d9.cpp | 24 +- 3rdparty/bgfx/src/renderer_d3d9.h | 6 +- 3rdparty/bgfx/src/renderer_gl.cpp | 111 +- 3rdparty/bgfx/src/renderer_gl.h | 66 +- 3rdparty/bgfx/src/renderer_gnm.cpp | 2 +- 3rdparty/bgfx/src/renderer_mtl.h | 29 +- 3rdparty/bgfx/src/renderer_mtl.mm | 258 +- 3rdparty/bgfx/src/renderer_noop.cpp | 4 +- 3rdparty/bgfx/src/renderer_nvn.cpp | 2 +- 3rdparty/bgfx/src/renderer_vk.cpp | 191 +- 3rdparty/bgfx/src/renderer_vk.h | 44 +- 3rdparty/bgfx/src/renderer_webgpu.cpp | 46 +- 3rdparty/bgfx/src/renderer_webgpu.h | 8 +- 3rdparty/bgfx/src/shader.cpp | 6 +- 3rdparty/bgfx/src/shader.h | 2 +- 3rdparty/bgfx/src/shader_dx9bc.cpp | 2 +- 3rdparty/bgfx/src/shader_dx9bc.h | 2 +- 3rdparty/bgfx/src/shader_dxbc.cpp | 4 +- 3rdparty/bgfx/src/shader_dxbc.h | 4 +- 3rdparty/bgfx/src/shader_spirv.cpp | 2 +- 3rdparty/bgfx/src/shader_spirv.h | 2 +- 3rdparty/bgfx/src/topology.cpp | 10 +- 3rdparty/bgfx/src/topology.h | 2 +- 3rdparty/bgfx/src/version.h | 6 +- 3rdparty/bgfx/src/vertexlayout.cpp | 6 +- 3rdparty/bgfx/src/vertexlayout.h | 2 +- 3rdparty/bgfx/src/vs_clear.sc | 2 +- 3rdparty/bgfx/src/vs_debugfont.sc | 2 +- 3rdparty/bgfx/tools/geometryc/geometryc.cpp | 85 +- 3rdparty/bgfx/tools/geometryv/geometryv.cpp | 6 +- 3rdparty/bgfx/tools/shaderc/shaderc.cpp | 145 +- 3rdparty/bgfx/tools/shaderc/shaderc.h | 12 +- 3rdparty/bgfx/tools/shaderc/shaderc_glsl.cpp | 38 +- 3rdparty/bgfx/tools/shaderc/shaderc_hlsl.cpp | 97 +- 3rdparty/bgfx/tools/shaderc/shaderc_metal.cpp | 158 +- 3rdparty/bgfx/tools/shaderc/shaderc_pssl.cpp | 9 +- 3rdparty/bgfx/tools/shaderc/shaderc_spirv.cpp | 70 +- 3rdparty/bgfx/tools/texturev/common.sh | 2 +- 3rdparty/bgfx/tools/texturev/fs_texture.sc | 2 +- 3rdparty/bgfx/tools/texturev/fs_texture_3d.sc | 2 +- 3rdparty/bgfx/tools/texturev/fs_texture_array.sc | 2 +- 3rdparty/bgfx/tools/texturev/fs_texture_cube.sc | 2 +- 3rdparty/bgfx/tools/texturev/fs_texture_cube2.sc | 2 +- 3rdparty/bgfx/tools/texturev/fs_texture_msdf.sc | 2 +- 3rdparty/bgfx/tools/texturev/fs_texture_sdf.sc | 2 +- 3rdparty/bgfx/tools/texturev/makefile | 2 +- 3rdparty/bgfx/tools/texturev/texturev.cpp | 6 +- 3rdparty/bgfx/tools/texturev/vs_texture.sc | 2 +- 3rdparty/bgfx/tools/texturev/vs_texture_cube.sc | 2 +- 3rdparty/bimg/.appveyor.yml | 20 + .../bimg/3rdparty/astc-encoder/include/astcenc.h | 57 +- .../source/astcenc_averages_and_directions.cpp | 59 +- .../astc-encoder/source/astcenc_block_sizes.cpp | 140 +- .../astc-encoder/source/astcenc_color_quantize.cpp | 150 +- .../source/astcenc_compress_symbolic.cpp | 70 +- .../source/astcenc_decompress_symbolic.cpp | 12 +- .../source/astcenc_diagnostic_trace.cpp | 19 +- .../3rdparty/astc-encoder/source/astcenc_entry.cpp | 169 +- .../source/astcenc_find_best_partitioning.cpp | 50 +- .../source/astcenc_ideal_endpoints_and_weights.cpp | 125 +- .../source/astcenc_integer_sequence.cpp | 127 +- .../astc-encoder/source/astcenc_internal.h | 140 +- .../3rdparty/astc-encoder/source/astcenc_mathlib.h | 2 + .../source/astcenc_mathlib_softfloat.cpp | 4 +- .../source/astcenc_partition_tables.cpp | 56 +- .../source/astcenc_percentile_tables.cpp | 4 +- .../source/astcenc_pick_best_endpoint_format.cpp | 33 +- .../source/astcenc_platform_isa_detection.cpp | 166 + .../astc-encoder/source/astcenc_quantization.cpp | 891 +- .../source/astcenc_symbolic_physical.cpp | 83 +- .../astc-encoder/source/astcenc_vecmathlib.h | 4 +- .../source/astcenc_vecmathlib_neon_4.h | 9 +- .../astc-encoder/source/astcenc_vecmathlib_sse_4.h | 14 +- .../astc-encoder/source/astcenc_weight_align.cpp | 6 +- .../source/astcenc_weight_quant_xfer_tables.cpp | 38 +- 3rdparty/bimg/3rdparty/lodepng/lodepng.cpp | 546 +- 3rdparty/bimg/3rdparty/lodepng/lodepng.h | 210 +- 3rdparty/bimg/3rdparty/nvtt/nvtt.cpp | 2 +- 3rdparty/bimg/LICENSE | 2 +- 3rdparty/bimg/README.md | 3 +- 3rdparty/bimg/include/bimg/bimg.h | 2 +- 3rdparty/bimg/include/bimg/decode.h | 2 +- 3rdparty/bimg/include/bimg/encode.h | 2 +- 3rdparty/bimg/makefile | 2 +- 3rdparty/bimg/scripts/bimg.lua | 2 +- 3rdparty/bimg/scripts/bimg_decode.lua | 2 +- 3rdparty/bimg/scripts/bimg_encode.lua | 2 +- 3rdparty/bimg/scripts/genie.lua | 2 +- 3rdparty/bimg/scripts/texturec.lua | 2 +- 3rdparty/bimg/src/bimg_p.h | 2 +- 3rdparty/bimg/src/config.h | 2 +- 3rdparty/bimg/src/image.cpp | 16 +- 3rdparty/bimg/src/image_cubemap_filter.cpp | 6 +- 3rdparty/bimg/src/image_decode.cpp | 6 +- 3rdparty/bimg/src/image_encode.cpp | 42 +- 3rdparty/bimg/src/image_gnf.cpp | 2 +- 3rdparty/bimg/tools/texturec/texturec.cpp | 111 +- 3rdparty/bx/.appveyor.yml | 19 + 3rdparty/bx/3rdparty/ini/ini.h | 105 +- 3rdparty/bx/LICENSE | 2 +- 3rdparty/bx/README.md | 5 +- 3rdparty/bx/include/bx/allocator.h | 60 +- 3rdparty/bx/include/bx/bounds.h | 46 +- 3rdparty/bx/include/bx/bx.h | 77 +- 3rdparty/bx/include/bx/commandline.h | 2 +- 3rdparty/bx/include/bx/config.h | 2 +- 3rdparty/bx/include/bx/constants.h | 43 +- 3rdparty/bx/include/bx/cpu.h | 2 +- 3rdparty/bx/include/bx/debug.h | 2 +- 3rdparty/bx/include/bx/easing.h | 2 +- 3rdparty/bx/include/bx/endian.h | 2 +- 3rdparty/bx/include/bx/error.h | 2 +- 3rdparty/bx/include/bx/file.h | 2 +- 3rdparty/bx/include/bx/filepath.h | 9 +- 3rdparty/bx/include/bx/float4x4_t.h | 2 +- 3rdparty/bx/include/bx/handlealloc.h | 2 +- 3rdparty/bx/include/bx/hash.h | 2 +- 3rdparty/bx/include/bx/inline/allocator.inl | 32 +- 3rdparty/bx/include/bx/inline/bounds.inl | 2 +- 3rdparty/bx/include/bx/inline/bx.inl | 2 +- 3rdparty/bx/include/bx/inline/cpu.inl | 2 +- 3rdparty/bx/include/bx/inline/easing.inl | 2 +- 3rdparty/bx/include/bx/inline/endian.inl | 2 +- 3rdparty/bx/include/bx/inline/error.inl | 2 +- 3rdparty/bx/include/bx/inline/float4x4_t.inl | 2 +- 3rdparty/bx/include/bx/inline/handlealloc.inl | 6 +- 3rdparty/bx/include/bx/inline/hash.inl | 2 +- 3rdparty/bx/include/bx/inline/math.inl | 140 +- 3rdparty/bx/include/bx/inline/mpscqueue.inl | 2 +- 3rdparty/bx/include/bx/inline/mutex.inl | 2 +- 3rdparty/bx/include/bx/inline/os.inl | 2 +- 3rdparty/bx/include/bx/inline/pixelformat.inl | 2 +- 3rdparty/bx/include/bx/inline/readerwriter.inl | 33 +- 3rdparty/bx/include/bx/inline/ringbuffer.inl | 2 +- 3rdparty/bx/include/bx/inline/rng.inl | 2 +- 3rdparty/bx/include/bx/inline/simd128_langext.inl | 2 +- 3rdparty/bx/include/bx/inline/simd128_neon.inl | 33 +- 3rdparty/bx/include/bx/inline/simd128_ref.inl | 2 +- 3rdparty/bx/include/bx/inline/simd128_sse.inl | 6 +- 3rdparty/bx/include/bx/inline/simd256_avx.inl | 2 +- 3rdparty/bx/include/bx/inline/simd256_ref.inl | 2 +- 3rdparty/bx/include/bx/inline/simd_ni.inl | 16 +- 3rdparty/bx/include/bx/inline/sort.inl | 8 +- 3rdparty/bx/include/bx/inline/spscqueue.inl | 6 +- 3rdparty/bx/include/bx/inline/string.inl | 52 +- 3rdparty/bx/include/bx/inline/typetraits.inl | 202 +- 3rdparty/bx/include/bx/inline/uint32_t.inl | 20 +- 3rdparty/bx/include/bx/macros.h | 52 +- 3rdparty/bx/include/bx/maputil.h | 2 +- 3rdparty/bx/include/bx/math.h | 70 +- 3rdparty/bx/include/bx/mpscqueue.h | 2 +- 3rdparty/bx/include/bx/mutex.h | 2 +- 3rdparty/bx/include/bx/os.h | 2 +- 3rdparty/bx/include/bx/pixelformat.h | 2 +- 3rdparty/bx/include/bx/platform.h | 18 +- 3rdparty/bx/include/bx/process.h | 2 +- 3rdparty/bx/include/bx/readerwriter.h | 5 +- 3rdparty/bx/include/bx/ringbuffer.h | 2 +- 3rdparty/bx/include/bx/rng.h | 2 +- 3rdparty/bx/include/bx/semaphore.h | 2 +- 3rdparty/bx/include/bx/settings.h | 2 +- 3rdparty/bx/include/bx/simd_t.h | 2 +- 3rdparty/bx/include/bx/sort.h | 2 +- 3rdparty/bx/include/bx/spscqueue.h | 2 +- 3rdparty/bx/include/bx/string.h | 58 +- 3rdparty/bx/include/bx/thread.h | 2 +- 3rdparty/bx/include/bx/timer.h | 2 +- 3rdparty/bx/include/bx/typetraits.h | 2 +- 3rdparty/bx/include/bx/uint32_t.h | 2 +- 3rdparty/bx/include/bx/url.h | 2 +- 3rdparty/bx/makefile | 2 +- 3rdparty/bx/scripts/bin2c.lua | 2 +- 3rdparty/bx/scripts/bx.lua | 2 +- 3rdparty/bx/scripts/genie.lua | 2 +- 3rdparty/bx/scripts/lemon.lua | 2 +- 3rdparty/bx/scripts/toolchain.lua | 16 +- 3rdparty/bx/src/allocator.cpp | 16 +- 3rdparty/bx/src/amalgamated.cpp | 2 +- 3rdparty/bx/src/bounds.cpp | 56 +- 3rdparty/bx/src/bx.cpp | 12 +- 3rdparty/bx/src/commandline.cpp | 2 +- 3rdparty/bx/src/crtnone.cpp | 2 +- 3rdparty/bx/src/debug.cpp | 2 +- 3rdparty/bx/src/dtoa.cpp | 2 +- 3rdparty/bx/src/easing.cpp | 2 +- 3rdparty/bx/src/file.cpp | 2 +- 3rdparty/bx/src/filepath.cpp | 62 +- 3rdparty/bx/src/hash.cpp | 2 +- 3rdparty/bx/src/math.cpp | 49 +- 3rdparty/bx/src/mutex.cpp | 2 +- 3rdparty/bx/src/os.cpp | 2 +- 3rdparty/bx/src/process.cpp | 2 +- 3rdparty/bx/src/semaphore.cpp | 2 +- 3rdparty/bx/src/settings.cpp | 14 +- 3rdparty/bx/src/sort.cpp | 2 +- 3rdparty/bx/src/string.cpp | 58 +- 3rdparty/bx/src/thread.cpp | 6 +- 3rdparty/bx/src/timer.cpp | 2 +- 3rdparty/bx/src/url.cpp | 2 +- 3rdparty/bx/tests/allocator_test.cpp | 8 +- 3rdparty/bx/tests/atomic_test.cpp | 2 +- 3rdparty/bx/tests/crt_test.cpp | 2 +- 3rdparty/bx/tests/dbg.h | 2 +- 3rdparty/bx/tests/easing_test.cpp | 2 +- 3rdparty/bx/tests/filepath_test.cpp | 33 +- 3rdparty/bx/tests/handle_bench.cpp | 2 +- 3rdparty/bx/tests/handle_test.cpp | 2 +- 3rdparty/bx/tests/hash_test.cpp | 2 +- 3rdparty/bx/tests/macros_test.cpp | 2 +- 3rdparty/bx/tests/main_test.cpp | 2 +- 3rdparty/bx/tests/math_bench.cpp | 2 +- 3rdparty/bx/tests/math_test.cpp | 288 +- 3rdparty/bx/tests/os_test.cpp | 2 +- 3rdparty/bx/tests/queue_test.cpp | 2 +- 3rdparty/bx/tests/readerwriter_test.cpp | 2 +- 3rdparty/bx/tests/ringbuffer_test.cpp | 2 +- 3rdparty/bx/tests/rng_test.cpp | 2 +- 3rdparty/bx/tests/run_test.cpp | 2 +- 3rdparty/bx/tests/settings_test.cpp | 2 +- 3rdparty/bx/tests/simd_bench.cpp | 6 +- 3rdparty/bx/tests/simd_test.cpp | 2 +- 3rdparty/bx/tests/sort_test.cpp | 62 +- 3rdparty/bx/tests/string_test.cpp | 93 +- 3rdparty/bx/tests/test.h | 2 +- 3rdparty/bx/tests/thread_test.cpp | 2 +- 3rdparty/bx/tests/tokenizecmd_test.cpp | 2 +- 3rdparty/bx/tests/typetraits_test.cpp | 2 +- 3rdparty/bx/tests/uint32_test.cpp | 34 +- 3rdparty/bx/tests/url_test.cpp | 4 +- 3rdparty/bx/tests/vsnprintf_test.cpp | 57 +- 3rdparty/bx/tools/bin2c/bin2c.cpp | 8 +- bgfx/shaders/metal/chains/blurs/vs_smart-blur.bin | Bin 1469 -> 1421 bytes bgfx/shaders/metal/chains/crt-geom/vs_crt-geom.bin | Bin 4182 -> 4134 bytes bgfx/shaders/metal/chains/crt-geom/vs_gaussx.bin | Bin 1275 -> 1227 bytes bgfx/shaders/metal/chains/crt-geom/vs_gaussy.bin | Bin 1275 -> 1227 bytes bgfx/shaders/metal/chains/crt-geom/vs_lowpass.bin | Bin 3505 -> 3457 bytes bgfx/shaders/metal/chains/crt-geom/vs_mipmap8.bin | Bin 738 -> 690 bytes .../metal/chains/crt-geom/vs_phosphor_apply.bin | Bin 738 -> 690 bytes .../metal/chains/crt-geom/vs_phosphor_update.bin | Bin 738 -> 690 bytes bgfx/shaders/metal/chains/crt/vs_crt-caligari.bin | Bin 1109 -> 1061 bytes bgfx/shaders/metal/chains/default/vs_blit.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/eagle/vs_eagle.bin | Bin 2420 -> 2372 bytes bgfx/shaders/metal/chains/hlsl/vs_chroma.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/hlsl/vs_color.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/hlsl/vs_deconverge.bin | Bin 2094 -> 2046 bytes bgfx/shaders/metal/chains/hlsl/vs_defocus.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/hlsl/vs_distortion.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/hlsl/vs_ntsc_decode.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/hlsl/vs_ntsc_encode.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/hlsl/vs_phosphor.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/hlsl/vs_post.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/hlsl/vs_prescale.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/hlsl/vs_scanline.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/hqx/vs_hq2x.bin | Bin 1469 -> 1421 bytes bgfx/shaders/metal/chains/hqx/vs_hq3x.bin | Bin 1469 -> 1421 bytes bgfx/shaders/metal/chains/hqx/vs_hq4x.bin | Bin 1469 -> 1421 bytes bgfx/shaders/metal/chains/lcd-grid/vs_lcd-grid.bin | Bin 883 -> 835 bytes .../metal/chains/lcd-grid/vs_persistence.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/misc/vs_blit.bin | Bin 883 -> 835 bytes .../chains/misc/vs_bob-and-ghost-deinterlace.bin | Bin 883 -> 835 bytes .../metal/chains/misc/vs_deposterize-pass0.bin | Bin 1222 -> 1174 bytes .../metal/chains/misc/vs_deposterize-pass1.bin | Bin 1222 -> 1174 bytes bgfx/shaders/metal/chains/misc/vs_lut.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/chains/misc/vs_resize_blit.bin | Bin 1014 -> 966 bytes bgfx/shaders/metal/chains/misc/vs_saturation.bin | Bin 883 -> 835 bytes .../pillarbox_left_horizontal/vs_gaussian.bin | Bin 883 -> 835 bytes .../pillarbox_left_horizontal/vs_offset_sat.bin | Bin 993 -> 945 bytes .../chains/pillarbox_left_vertical/vs_gaussian.bin | Bin 883 -> 835 bytes .../pillarbox_left_vertical/vs_offset_sat.bin | Bin 991 -> 943 bytes .../pillarbox_right_horizontal/vs_gaussian.bin | Bin 883 -> 835 bytes .../pillarbox_right_horizontal/vs_offset_sat.bin | Bin 999 -> 951 bytes .../pillarbox_right_vertical/vs_gaussian.bin | Bin 883 -> 835 bytes .../pillarbox_right_vertical/vs_offset_sat.bin | Bin 1020 -> 972 bytes bgfx/shaders/metal/chains/unfiltered/vs_blit.bin | Bin 883 -> 835 bytes .../chains/warp/vs_dilation-horizontal-fast.bin | Bin 1082 -> 1034 bytes .../xbr/super-xbr/vs_custom-jinc2-sharper.bin | Bin 883 -> 835 bytes .../xbr/super-xbr/vs_super-2xbr-3d-pass0.bin | Bin 883 -> 835 bytes .../xbr/super-xbr/vs_super-2xbr-3d-pass1.bin | Bin 883 -> 835 bytes .../xbr/super-xbr/vs_super-2xbr-3d-pass2.bin | Bin 1678 -> 1630 bytes .../xbr/super-xbr/vs_super-4xbr-3d-pass0.bin | Bin 883 -> 835 bytes .../xbr/super-xbr/vs_super-4xbr-3d-pass1.bin | Bin 883 -> 835 bytes .../xbr/super-xbr/vs_super-4xbr-3d-pass1f.bin | Bin 1678 -> 1630 bytes .../xbr/super-xbr/vs_super-4xbr-3d-pass2.bin | Bin 883 -> 835 bytes .../xbr/super-xbr/vs_super-4xbr-3d-pass3.bin | Bin 883 -> 835 bytes .../xbr/super-xbr/vs_super-4xbr-3d-pass3f.bin | Bin 1678 -> 1630 bytes .../xbr/super-xbr/vs_super-xbr-fast-pass0.bin | Bin 883 -> 835 bytes .../xbr/super-xbr/vs_super-xbr-fast-pass1.bin | Bin 883 -> 835 bytes .../xbr/super-xbr/vs_super-xbr-fast-pass2.bin | Bin 883 -> 835 bytes .../chains/xbr/super-xbr/vs_super-xbr-pass0.bin | Bin 1666 -> 1618 bytes .../chains/xbr/super-xbr/vs_super-xbr-pass1.bin | Bin 883 -> 835 bytes .../chains/xbr/super-xbr/vs_super-xbr-pass2.bin | Bin 1678 -> 1630 bytes .../chains/xbr/super-xbr/vs_super-xbr-pass3.bin | Bin 1678 -> 1630 bytes .../metal/chains/xbr/vs_xbr-lv1-noblend.bin | Bin 1181 -> 1070 bytes bgfx/shaders/metal/chains/xbr/vs_xbr-lv2-3d.bin | Bin 2172 -> 2124 bytes bgfx/shaders/metal/chains/xbr/vs_xbr-lv2-fast.bin | Bin 1469 -> 1421 bytes .../metal/chains/xbr/vs_xbr-lv2-noblend.bin | Bin 2128 -> 2080 bytes bgfx/shaders/metal/chains/xbr/vs_xbr-lv2.bin | Bin 2128 -> 2080 bytes .../metal/chains/xbr/vs_xbr-lv3-noblend.bin | Bin 2128 -> 2080 bytes bgfx/shaders/metal/chains/xbr/vs_xbr-lv3.bin | Bin 2128 -> 2080 bytes .../chains/xbr/xbr-hybrid/vs_2xbr-hybrid-sharp.bin | Bin 2128 -> 2080 bytes .../xbr/xbr-hybrid/vs_2xbr-hybrid-v2-gamma.bin | Bin 2128 -> 2080 bytes .../chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v2.bin | Bin 2128 -> 2080 bytes .../xbr/xbr-hybrid/vs_2xbr-hybrid-v4-gamma.bin | Bin 2128 -> 2080 bytes .../chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4.bin | Bin 2128 -> 2080 bytes .../chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4b.bin | Bin 2128 -> 2080 bytes .../xbr/xbr-hybrid/vs_2xbr-hybrid-v5-gamma.bin | Bin 2128 -> 2080 bytes .../metal/chains/xbr/xbr-hybrid/vs_2xbr-hybrid.bin | Bin 2128 -> 2080 bytes .../xbr/xbr-lv2-multipass/vs_xbr-lv2-a-pass0.bin | Bin 2128 -> 2080 bytes .../vs_xbr-lv2-accuracy-pass0.bin | Bin 2128 -> 2080 bytes .../vs_xbr-lv2-accuracy-pass1.bin | Bin 1336 -> 1288 bytes .../xbr/xbr-lv2-multipass/vs_xbr-lv2-b-pass0.bin | Bin 2128 -> 2080 bytes .../xbr/xbr-lv2-multipass/vs_xbr-lv2-c-pass0.bin | Bin 2128 -> 2080 bytes .../xbr/xbr-lv2-multipass/vs_xbr-lv2-d-pass0.bin | Bin 2128 -> 2080 bytes .../xbr-lv2-multipass/vs_xbr-lv2-noblend-pass1.bin | Bin 1336 -> 1288 bytes .../xbr/xbr-lv2-multipass/vs_xbr-lv2-pass1.bin | Bin 1336 -> 1288 bytes .../xbr/xbr-lv3-multipass/vs_xbr-lv3-pass0.bin | Bin 2128 -> 2080 bytes .../xbr/xbr-lv3-multipass/vs_xbr-lv3-pass1.bin | Bin 1384 -> 1336 bytes .../xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass1.bin | Bin 1066 -> 1018 bytes .../xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass2.bin | Bin 2128 -> 2080 bytes .../xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass3.bin | Bin 1116 -> 1068 bytes .../xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass4.bin | Bin 1116 -> 1068 bytes bgfx/shaders/metal/vs_gui.bin | Bin 883 -> 835 bytes bgfx/shaders/metal/vs_screen.bin | Bin 883 -> 835 bytes .../spirv/chains/xbr/vs_xbr-lv1-noblend.bin | Bin 1723 -> 1651 bytes scripts/src/3rdparty.lua | 2 + src/osd/modules/render/bgfx/shaders/shader.mk | 10 +- 1156 files changed, 40981 insertions(+), 57943 deletions(-) delete mode 100644 3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.ARM.h mode change 100755 => 100644 3rdparty/bgfx/3rdparty/glslang/SPIRV/GlslangToSpv.cpp mode change 100755 => 100644 3rdparty/bgfx/3rdparty/glslang/SPIRV/doc.cpp create mode 100644 3rdparty/bgfx/3rdparty/glslang/StandAlone/ResourceLimits.cpp create mode 100644 3rdparty/bgfx/3rdparty/glslang/StandAlone/resource_limits_c.cpp mode change 100755 => 100644 3rdparty/bgfx/3rdparty/glslang/glslang/Include/BaseTypes.h mode change 100755 => 100644 3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/Initialize.cpp mode change 100755 => 100644 3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/Versions.h create mode 100644 3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/glslang.m4 delete mode 100644 3rdparty/bgfx/3rdparty/glslang/glslang/ResourceLimits/ResourceLimits.cpp delete mode 100644 3rdparty/bgfx/3rdparty/glslang/glslang/ResourceLimits/resource_limits_c.cpp create mode 100644 3rdparty/bgfx/3rdparty/glslang/hlsl/stub.cpp create mode 100644 3rdparty/bgfx/3rdparty/khronos/GLES3/gl3ext.h create mode 100644 3rdparty/bgfx/3rdparty/khronos/gl/GRemedyGLExtensions.h delete mode 100644 3rdparty/bgfx/3rdparty/khronos/vulkan-local/vk_video/vulkan_video_codec_h264std.h delete mode 100644 3rdparty/bgfx/3rdparty/khronos/vulkan-local/vk_video/vulkan_video_codec_h264std_decode.h delete mode 100644 3rdparty/bgfx/3rdparty/khronos/vulkan-local/vk_video/vulkan_video_codec_h264std_encode.h delete mode 100644 3rdparty/bgfx/3rdparty/khronos/vulkan-local/vk_video/vulkan_video_codec_h265std.h delete mode 100644 3rdparty/bgfx/3rdparty/khronos/vulkan-local/vk_video/vulkan_video_codec_h265std_decode.h delete mode 100644 3rdparty/bgfx/3rdparty/khronos/vulkan-local/vk_video/vulkan_video_codec_h265std_encode.h delete mode 100644 3rdparty/bgfx/3rdparty/khronos/vulkan-local/vk_video/vulkan_video_codecs_common.h delete mode 100644 3rdparty/bgfx/3rdparty/khronos/wgl/wgl.h delete mode 100644 3rdparty/bgfx/3rdparty/spirv-headers/include/spirv/1.0/spirv.hpp11 delete mode 100644 3rdparty/bgfx/3rdparty/spirv-headers/include/spirv/1.1/spirv.hpp11 delete mode 100644 3rdparty/bgfx/3rdparty/spirv-headers/include/spirv/1.2/spirv.hpp11 delete mode 100644 3rdparty/bgfx/3rdparty/spirv-headers/include/spirv/unified1/NonSemanticDebugBreak.h delete mode 100644 3rdparty/bgfx/3rdparty/spirv-headers/include/spirv/unified1/extinst.nonsemantic.debugbreak.grammar.json delete mode 100644 3rdparty/bgfx/3rdparty/spirv-headers/include/spirv/unified1/spirv.hpp11 delete mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/analyze_live_input_pass.cpp delete mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/analyze_live_input_pass.h create mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/eliminate_dead_input_components_pass.cpp create mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/eliminate_dead_input_components_pass.h delete mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/eliminate_dead_io_components_pass.cpp delete mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/eliminate_dead_io_components_pass.h delete mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/eliminate_dead_output_stores_pass.cpp delete mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/eliminate_dead_output_stores_pass.h delete mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/liveness.cpp delete mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/liveness.h delete mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/trim_capabilities_pass.cpp delete mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/trim_capabilities_pass.h delete mode 100644 3rdparty/bgfx/3rdparty/spirv-tools/source/val/validate_ray_tracing_reorder.cpp delete mode 100644 3rdparty/bgfx/README.mame delete mode 100644 3rdparty/bgfx/bindings/d/fakeenum.d create mode 100644 3rdparty/bgfx/bindings/d/funcs.d delete mode 100644 3rdparty/bgfx/bindings/d/package.d create mode 100644 3rdparty/bgfx/bindings/d/types.d create mode 100644 3rdparty/bgfx/src/glcontext_glx.cpp create mode 100644 3rdparty/bgfx/src/glcontext_glx.h create mode 100644 3rdparty/bimg/.appveyor.yml create mode 100644 3rdparty/bimg/3rdparty/astc-encoder/source/astcenc_platform_isa_detection.cpp create mode 100644 3rdparty/bx/.appveyor.yml diff --git a/3rdparty/bgfx/.github/workflows/main.yml b/3rdparty/bgfx/.github/workflows/main.yml index 2c55b27554c..63772b046ee 100644 --- a/3rdparty/bgfx/.github/workflows/main.yml +++ b/3rdparty/bgfx/.github/workflows/main.yml @@ -211,7 +211,10 @@ jobs: fail-fast: true matrix: include: [ + { platform: arm }, { platform: arm64 }, + { platform: x86 }, + { platform: x86_64 }, ] name: android-${{ matrix.platform }} runs-on: ubuntu-22.04 diff --git a/3rdparty/bgfx/3rdparty/cgltf/cgltf.h b/3rdparty/bgfx/3rdparty/cgltf/cgltf.h index af24c65e0af..0e9c67eaa55 100644 --- a/3rdparty/bgfx/3rdparty/cgltf/cgltf.h +++ b/3rdparty/bgfx/3rdparty/cgltf/cgltf.h @@ -65,8 +65,7 @@ * * `cgltf_num_components` is a tiny utility that tells you the dimensionality of * a certain accessor type. This can be used before `cgltf_accessor_unpack_floats` to help allocate - * the necessary amount of memory. `cgltf_component_size` and `cgltf_calc_size` exist for - * similar purposes. + * the necessary amount of memory. * * `cgltf_accessor_read_float` reads a certain element from a non-sparse accessor and converts it to * floating point, assuming that `cgltf_load_buffers` has already been called. The passed-in element @@ -504,13 +503,6 @@ typedef struct cgltf_iridescence cgltf_texture_view iridescence_thickness_texture; } cgltf_iridescence; -typedef struct cgltf_anisotropy -{ - cgltf_float anisotropy_strength; - cgltf_float anisotropy_rotation; - cgltf_texture_view anisotropy_texture; -} cgltf_anisotropy; - typedef struct cgltf_material { char* name; @@ -524,7 +516,6 @@ typedef struct cgltf_material cgltf_bool has_sheen; cgltf_bool has_emissive_strength; cgltf_bool has_iridescence; - cgltf_bool has_anisotropy; cgltf_pbr_metallic_roughness pbr_metallic_roughness; cgltf_pbr_specular_glossiness pbr_specular_glossiness; cgltf_clearcoat clearcoat; @@ -535,7 +526,6 @@ typedef struct cgltf_material cgltf_volume volume; cgltf_emissive_strength emissive_strength; cgltf_iridescence iridescence; - cgltf_anisotropy anisotropy; cgltf_texture_view normal_texture; cgltf_texture_view occlusion_texture; cgltf_texture_view emissive_texture; @@ -568,6 +558,7 @@ typedef struct cgltf_draco_mesh_compression { } cgltf_draco_mesh_compression; typedef struct cgltf_mesh_gpu_instancing { + cgltf_buffer_view* buffer_view; cgltf_attribute* attributes; cgltf_size attributes_count; } cgltf_mesh_gpu_instancing; @@ -846,32 +837,12 @@ cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size i cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index); cgltf_size cgltf_num_components(cgltf_type type); -cgltf_size cgltf_component_size(cgltf_component_type component_type); -cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type); cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count); -cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, cgltf_uint* out, cgltf_size index_count); /* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size); -cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object); -cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object); -cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object); -cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object); -cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object); -cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object); -cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object); -cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object); -cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object); -cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object); -cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object); -cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object); -cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object); -cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object); -cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object); -cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object); - #ifdef __cplusplus } #endif @@ -892,7 +863,6 @@ cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const #ifdef CGLTF_IMPLEMENTATION -#include /* For assert */ #include /* For strncpy */ #include /* For fopen */ #include /* For UINT_MAX etc */ @@ -902,6 +872,10 @@ cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const #include /* For malloc, free, atoi, atof */ #endif +#if CGLTF_VALIDATE_ENABLE_ASSERTS +#include +#endif + /* JSMN_PARENT_LINKS is necessary to make parsing large structures linear in input size */ #define JSMN_PARENT_LINKS @@ -930,15 +904,15 @@ enum jsmnerr { }; typedef struct { jsmntype_t type; - ptrdiff_t start; - ptrdiff_t end; + int start; + int end; int size; #ifdef JSMN_PARENT_LINKS int parent; #endif } jsmntok_t; typedef struct { - size_t pos; /* offset in the JSON string */ + unsigned int pos; /* offset in the JSON string */ unsigned int toknext; /* next token to allocate */ int toksuper; /* superior token node, e.g parent object or array */ } jsmn_parser; @@ -1023,7 +997,7 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m { fseek(file, 0, SEEK_END); -#ifdef _MSC_VER +#ifdef _WIN32 __int64 length = _ftelli64(file); #else long length = ftell(file); @@ -1514,6 +1488,8 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, return cgltf_result_success; } +static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type); + static cgltf_size cgltf_calc_index_bound(cgltf_buffer_view* buffer_view, cgltf_size offset, cgltf_component_type component_type, cgltf_size count) { char* data = (char*)buffer_view->buffer->data + offset + buffer_view->offset; @@ -1962,10 +1938,6 @@ void cgltf_free(cgltf_data* data) cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_texture); cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_thickness_texture); } - if (data->materials[i].has_anisotropy) - { - cgltf_free_texture_view(data, &data->materials[i].anisotropy.anisotropy_texture); - } cgltf_free_texture_view(data, &data->materials[i].normal_texture); cgltf_free_texture_view(data, &data->materials[i].occlusion_texture); @@ -2245,7 +2217,7 @@ static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_typ case cgltf_component_type_r_32u: return *((const uint32_t*) in); case cgltf_component_type_r_32f: - return (cgltf_size)((cgltf_ssize)*((const float*) in)); + return (cgltf_size)*((const float*) in); case cgltf_component_type_r_8u: return *((const uint8_t*) in); default: @@ -2281,6 +2253,8 @@ static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_ty return (cgltf_float)cgltf_component_read_integer(in, component_type); } +static cgltf_size cgltf_component_size(cgltf_component_type component_type); + static cgltf_bool cgltf_element_read_float(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_bool normalized, cgltf_float* out, cgltf_size element_size) { cgltf_size num_components = cgltf_num_components(type); @@ -2383,41 +2357,21 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl cgltf_size element_count = float_count / floats_per_element; // First pass: convert each element in the base accessor. - if (accessor->buffer_view == NULL) - { - memset(out, 0, element_count * floats_per_element * sizeof(cgltf_float)); - } - else + cgltf_float* dest = out; + cgltf_accessor dense = *accessor; + dense.is_sparse = 0; + for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element) { - const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view); - if (element == NULL) + if (!cgltf_accessor_read_float(&dense, index, dest, floats_per_element)) { return 0; } - element += accessor->offset; - - if (accessor->component_type == cgltf_component_type_r_32f && accessor->stride == floats_per_element * sizeof(cgltf_float)) - { - memcpy(out, element, element_count * floats_per_element * sizeof(cgltf_float)); - } - else - { - cgltf_float* dest = out; - - for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element, element += accessor->stride) - { - if (!cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, dest, floats_per_element)) - { - return 0; - } - } - } } // Second pass: write out each element in the sparse accessor. if (accessor->is_sparse) { - const cgltf_accessor_sparse* sparse = &accessor->sparse; + const cgltf_accessor_sparse* sparse = &dense.sparse; const uint8_t* index_data = cgltf_buffer_view_data(sparse->indices_buffer_view); const uint8_t* reader_head = cgltf_buffer_view_data(sparse->values_buffer_view); @@ -2431,15 +2385,17 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl reader_head += sparse->values_byte_offset; cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type); - for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride, reader_head += accessor->stride) + for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride) { size_t writer_index = cgltf_component_read_index(index_data, sparse->indices_component_type); float* writer_head = out + writer_index * floats_per_element; - if (!cgltf_element_read_float(reader_head, accessor->type, accessor->component_type, accessor->normalized, writer_head, floats_per_element)) + if (!cgltf_element_read_float(reader_head, dense.type, dense.component_type, dense.normalized, writer_head, floats_per_element)) { return 0; } + + reader_head += dense.stride; } } @@ -2533,143 +2489,6 @@ cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size return cgltf_component_read_index(element, accessor->component_type); } -cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object) -{ - assert(object && (cgltf_size)(object - data->meshes) < data->meshes_count); - return (cgltf_size)(object - data->meshes); -} - -cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object) -{ - assert(object && (cgltf_size)(object - data->materials) < data->materials_count); - return (cgltf_size)(object - data->materials); -} - -cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object) -{ - assert(object && (cgltf_size)(object - data->accessors) < data->accessors_count); - return (cgltf_size)(object - data->accessors); -} - -cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object) -{ - assert(object && (cgltf_size)(object - data->buffer_views) < data->buffer_views_count); - return (cgltf_size)(object - data->buffer_views); -} - -cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object) -{ - assert(object && (cgltf_size)(object - data->buffers) < data->buffers_count); - return (cgltf_size)(object - data->buffers); -} - -cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object) -{ - assert(object && (cgltf_size)(object - data->images) < data->images_count); - return (cgltf_size)(object - data->images); -} - -cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object) -{ - assert(object && (cgltf_size)(object - data->textures) < data->textures_count); - return (cgltf_size)(object - data->textures); -} - -cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object) -{ - assert(object && (cgltf_size)(object - data->samplers) < data->samplers_count); - return (cgltf_size)(object - data->samplers); -} - -cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object) -{ - assert(object && (cgltf_size)(object - data->skins) < data->skins_count); - return (cgltf_size)(object - data->skins); -} - -cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object) -{ - assert(object && (cgltf_size)(object - data->cameras) < data->cameras_count); - return (cgltf_size)(object - data->cameras); -} - -cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object) -{ - assert(object && (cgltf_size)(object - data->lights) < data->lights_count); - return (cgltf_size)(object - data->lights); -} - -cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object) -{ - assert(object && (cgltf_size)(object - data->nodes) < data->nodes_count); - return (cgltf_size)(object - data->nodes); -} - -cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object) -{ - assert(object && (cgltf_size)(object - data->scenes) < data->scenes_count); - return (cgltf_size)(object - data->scenes); -} - -cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object) -{ - assert(object && (cgltf_size)(object - data->animations) < data->animations_count); - return (cgltf_size)(object - data->animations); -} - -cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object) -{ - assert(object && (cgltf_size)(object - animation->samplers) < animation->samplers_count); - return (cgltf_size)(object - animation->samplers); -} - -cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object) -{ - assert(object && (cgltf_size)(object - animation->channels) < animation->channels_count); - return (cgltf_size)(object - animation->channels); -} - -cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, cgltf_uint* out, cgltf_size index_count) -{ - if (out == NULL) - { - return accessor->count; - } - - index_count = accessor->count < index_count ? accessor->count : index_count; - - if (accessor->is_sparse) - { - return 0; - } - if (accessor->buffer_view == NULL) - { - return 0; - } - const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view); - if (element == NULL) - { - return 0; - } - element += accessor->offset; - - if (accessor->component_type == cgltf_component_type_r_32u && accessor->stride == sizeof(cgltf_uint)) - { - memcpy(out, element, index_count * sizeof(cgltf_uint)); - } - else - { - cgltf_uint* dest = out; - - for (cgltf_size index = 0; index < index_count; index++, dest++, element += accessor->stride) - { - *dest = (cgltf_uint)cgltf_component_read_index(element, accessor->component_type); - } - } - - return index_count; -} - #define CGLTF_ERROR_JSON -1 #define CGLTF_ERROR_NOMEM -2 #define CGLTF_ERROR_LEGACY -3 @@ -2686,7 +2505,7 @@ static int cgltf_json_strcmp(jsmntok_t const* tok, const uint8_t* json_chunk, co { CGLTF_CHECK_TOKTYPE(*tok, JSMN_STRING); size_t const str_len = strlen(str); - size_t const name_length = (size_t)(tok->end - tok->start); + size_t const name_length = tok->end - tok->start; return (str_len == name_length) ? strncmp((const char*)json_chunk + tok->start, str, str_len) : 128; } @@ -2694,7 +2513,7 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk) { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); + int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return CGLTF_ATOI(tmp); @@ -2704,7 +2523,7 @@ static cgltf_size cgltf_json_to_size(jsmntok_t const* tok, const uint8_t* json_c { CGLTF_CHECK_TOKTYPE_RETTYPE(*tok, JSMN_PRIMITIVE, cgltf_size); char tmp[128]; - int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); + int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return (cgltf_size)CGLTF_ATOLL(tmp); @@ -2714,7 +2533,7 @@ static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); + int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return (cgltf_float)CGLTF_ATOF(tmp); @@ -2722,7 +2541,7 @@ static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json static cgltf_bool cgltf_json_to_bool(jsmntok_t const* tok, const uint8_t* json_chunk) { - int size = (int)(tok->end - tok->start); + int size = tok->end - tok->start; return size == 4 && memcmp(json_chunk + tok->start, "true", 4) == 0; } @@ -2788,7 +2607,7 @@ static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* toke { return CGLTF_ERROR_JSON; } - int size = (int)(tokens[i].end - tokens[i].start); + int size = tokens[i].end - tokens[i].start; char* result = (char*)options->memory.alloc_func(options->memory.user_data, size + 1); if (!result) { @@ -3046,10 +2865,6 @@ static int cgltf_parse_json_draco_mesh_compression(cgltf_options* options, jsmnt out_draco_mesh_compression->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); ++i; } - else - { - i = cgltf_skip_json(tokens, i+1); - } if (i < 0) { @@ -3075,9 +2890,11 @@ static int cgltf_parse_json_mesh_gpu_instancing(cgltf_options* options, jsmntok_ { i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_mesh_gpu_instancing->attributes, &out_mesh_gpu_instancing->attributes_count); } - else + else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferView") == 0) { - i = cgltf_skip_json(tokens, i+1); + ++i; + out_mesh_gpu_instancing->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; } if (i < 0) @@ -4312,47 +4129,6 @@ static int cgltf_parse_json_iridescence(cgltf_options* options, jsmntok_t const* return i; } -static int cgltf_parse_json_anisotropy(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_anisotropy* out_anisotropy) -{ - CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - int size = tokens[i].size; - ++i; - - - for (int j = 0; j < size; ++j) - { - CGLTF_CHECK_KEY(tokens[i]); - - if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyStrength") == 0) - { - ++i; - out_anisotropy->anisotropy_strength = cgltf_json_to_float(tokens + i, json_chunk); - ++i; - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyRotation") == 0) - { - ++i; - out_anisotropy->anisotropy_rotation = cgltf_json_to_float(tokens + i, json_chunk); - ++i; - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyTexture") == 0) - { - i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_anisotropy->anisotropy_texture); - } - else - { - i = cgltf_skip_json(tokens, i + 1); - } - - if (i < 0) - { - return i; - } - } - - return i; -} - static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_image* out_image) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -4741,11 +4517,6 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to out_material->has_iridescence = 1; i = cgltf_parse_json_iridescence(options, tokens, i + 1, json_chunk, &out_material->iridescence); } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_anisotropy") == 0) - { - out_material->has_anisotropy = 1; - i = cgltf_parse_json_anisotropy(options, tokens, i + 1, json_chunk, &out_material->anisotropy); - } else { i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_material->extensions[out_material->extensions_count++])); @@ -6194,7 +5965,7 @@ cgltf_size cgltf_num_components(cgltf_type type) { } } -cgltf_size cgltf_component_size(cgltf_component_type component_type) { +static cgltf_size cgltf_component_size(cgltf_component_type component_type) { switch (component_type) { case cgltf_component_type_r_8: @@ -6212,7 +5983,7 @@ cgltf_size cgltf_component_size(cgltf_component_type component_type) { } } -cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type) +static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type) { cgltf_size component_size = cgltf_component_size(component_type); if (type == cgltf_type_mat2 && component_size == 1) @@ -6597,8 +6368,6 @@ static int cgltf_fixup_pointers(cgltf_data* data) CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_texture.texture, data->textures, data->textures_count); CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_thickness_texture.texture, data->textures, data->textures_count); - - CGLTF_PTRFIXUP(data->materials[i].anisotropy.anisotropy_texture.texture, data->textures, data->textures_count); } for (cgltf_size i = 0; i < data->buffer_views_count; ++i) @@ -6643,6 +6412,7 @@ static int cgltf_fixup_pointers(cgltf_data* data) if (data->nodes[i].has_mesh_gpu_instancing) { + CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.buffer_view, data->buffer_views, data->buffer_views_count); for (cgltf_size m = 0; m < data->nodes[i].mesh_gpu_instancing.attributes_count; ++m) { CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.attributes[m].data, data->accessors, data->accessors_count); @@ -6731,7 +6501,7 @@ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, * Fills token type and boundaries. */ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, - ptrdiff_t start, ptrdiff_t end) { + int start, int end) { token->type = type; token->start = start; token->end = end; @@ -6744,7 +6514,7 @@ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; - ptrdiff_t start; + int start; start = parser->pos; @@ -6794,7 +6564,7 @@ static int jsmn_parse_string(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; - ptrdiff_t start = parser->pos; + int start = parser->pos; parser->pos++; diff --git a/3rdparty/bgfx/3rdparty/cgltf/cgltf_write.h b/3rdparty/bgfx/3rdparty/cgltf/cgltf_write.h index be22b888c83..033b0d1ccab 100644 --- a/3rdparty/bgfx/3rdparty/cgltf/cgltf_write.h +++ b/3rdparty/bgfx/3rdparty/cgltf/cgltf_write.h @@ -85,7 +85,6 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si #define CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH (1 << 13) #define CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING (1 << 14) #define CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE (1 << 15) -#define CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY (1 << 16) typedef struct { char* buffer; @@ -642,11 +641,6 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE; } - if (material->has_anisotropy) - { - context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY; - } - if (material->has_pbr_metallic_roughness) { const cgltf_pbr_metallic_roughness* params = &material->pbr_metallic_roughness; @@ -662,7 +656,7 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater cgltf_write_line(context, "}"); } - if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence || material->has_anisotropy) + if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence) { cgltf_write_line(context, "\"extensions\": {"); if (material->has_clearcoat) @@ -773,15 +767,6 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater CGLTF_WRITE_TEXTURE_INFO("iridescenceThicknessTexture", params->iridescence_thickness_texture); cgltf_write_line(context, "}"); } - if (material->has_anisotropy) - { - cgltf_write_line(context, "\"KHR_materials_anisotropy\": {"); - const cgltf_anisotropy* params = &material->anisotropy; - cgltf_write_floatprop(context, "anisotropyFactor", params->anisotropy_strength, 0.f); - cgltf_write_floatprop(context, "anisotropyRotation", params->anisotropy_rotation, 0.f); - CGLTF_WRITE_TEXTURE_INFO("anisotropyTexture", params->anisotropy_texture); - cgltf_write_line(context, "}"); - } cgltf_write_line(context, "}"); } @@ -992,6 +977,7 @@ static void cgltf_write_node(cgltf_write_context* context, const cgltf_node* nod cgltf_write_line(context, "\"EXT_mesh_gpu_instancing\": {"); { + CGLTF_WRITE_IDXPROP("bufferView", node->mesh_gpu_instancing.buffer_view, context->data->buffer_views); cgltf_write_line(context, "\"attributes\": {"); { for (cgltf_size i = 0; i < node->mesh_gpu_instancing.attributes_count; ++i) @@ -1137,7 +1123,6 @@ static void cgltf_write_light(cgltf_write_context* context, const cgltf_light* l cgltf_write_floatprop(context, "outerConeAngle", light->spot_outer_cone_angle, 3.14159265358979323846f/4.0f); cgltf_write_line(context, "}"); } - cgltf_write_extras( context, &light->extras ); cgltf_write_line(context, "}"); } @@ -1264,9 +1249,6 @@ static void cgltf_write_extensions(cgltf_write_context* context, uint32_t extens if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE) { cgltf_write_stritem(context, "KHR_materials_iridescence"); } - if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY) { - cgltf_write_stritem(context, "KHR_materials_anisotropy"); - } if (extension_flags & CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING) { cgltf_write_stritem(context, "EXT_mesh_gpu_instancing"); } diff --git a/3rdparty/bgfx/3rdparty/dear-imgui/imgui.cpp b/3rdparty/bgfx/3rdparty/dear-imgui/imgui.cpp index 9a34c717aba..bd3f95d77ae 100644 --- a/3rdparty/bgfx/3rdparty/dear-imgui/imgui.cpp +++ b/3rdparty/bgfx/3rdparty/dear-imgui/imgui.cpp @@ -1,34 +1,30 @@ -// dear imgui, v1.89.8 WIP +// dear imgui, v1.90 WIP // (main code and documentation) // Help: -// - Read FAQ at http://dearimgui.com/faq +// - Read FAQ at http://dearimgui.org/faq // - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. // Read imgui.cpp for details, links and comments. // Resources: -// - FAQ http://dearimgui.com/faq -// - Homepage https://github.com/ocornut/imgui +// - FAQ http://dearimgui.org/faq +// - Homepage & latest https://github.com/ocornut/imgui // - Releases & changelog https://github.com/ocornut/imgui/releases -// - Gallery https://github.com/ocornut/imgui/issues/6478 (please post your screenshots/video there!) +// - Gallery https://github.com/ocornut/imgui/issues/5243 (please post your screenshots/video there!) // - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) -// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started // - Glossary https://github.com/ocornut/imgui/wiki/Glossary // - Issues & support https://github.com/ocornut/imgui/issues -// - Tests & Automation https://github.com/ocornut/imgui_test_engine // Getting Started? -// - Read https://github.com/ocornut/imgui/wiki/Getting-Started -// - For first-time users having issues compiling/linking/running/loading fonts: +// - For first-time users having issues compiling/linking/running or issues loading fonts: // please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. // See LICENSE.txt for copyright and licensing details (standard MIT License). // This library is free but needs your support to sustain development and maintenance. -// Businesses: you can support continued development via B2B invoiced technical support, maintenance and sponsoring contracts. -// PLEASE reach out at contact AT dearimgui DOT com. See https://github.com/ocornut/imgui/wiki/Sponsors -// Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine. +// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.com". +// Individuals: you can support continued development via donations. See docs/README or web page. // It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library. // Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without @@ -43,16 +39,17 @@ Index of this file: DOCUMENTATION - MISSION STATEMENT -- CONTROLS GUIDE +- END-USER GUIDE - PROGRAMMER GUIDE - READ FIRST - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE - HOW A SIMPLE APPLICATION MAY LOOK LIKE - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE + - USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS - API BREAKING CHANGES (read me when you update!) - FREQUENTLY ASKED QUESTIONS (FAQ) - - Read all answers online: https://www.dearimgui.com/faq, or in docs/FAQ.md (with a Markdown viewer) + - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer) CODE (search for "[SECTION]" in the code to find them) @@ -72,7 +69,6 @@ CODE // [SECTION] ImGuiListClipper // [SECTION] STYLING // [SECTION] RENDER HELPERS -// [SECTION] INITIALIZATION, SHUTDOWN // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) // [SECTION] INPUTS // [SECTION] ERROR CHECKING @@ -111,80 +107,33 @@ CODE - Portable, minimize dependencies, run on target (consoles, phones, etc.). - Efficient runtime and memory consumption. - Designed primarily for developers and content-creators, not the typical end-user! - Some of the current weaknesses (which we aim to address in the future) includes: + Designed for developers and content-creators, not the typical end-user! Some of the current weaknesses includes: - - Doesn't look fancy. + - Doesn't look fancy, doesn't animate. - Limited layout features, intricate layouts are typically crafted in code. - CONTROLS GUIDE + END-USER GUIDE ============== - - MOUSE CONTROLS - - Mouse wheel: Scroll vertically. - - SHIFT+Mouse wheel: Scroll horizontally. - - Click [X]: Close a window, available when 'bool* p_open' is passed to ImGui::Begin(). - - Click ^, Double-Click title: Collapse window. - - Drag on corner/border: Resize window (double-click to auto fit window to its contents). - - Drag on any empty space: Move window (unless io.ConfigWindowsMoveFromTitleBarOnly = true). - - Left-click outside popup: Close popup stack (right-click over underlying popup: Partially close popup stack). - - - TEXT EDITOR - - Hold SHIFT or Drag Mouse: Select text. - - CTRL+Left/Right: Word jump. - - CTRL+Shift+Left/Right: Select words. - - CTRL+A or Double-Click: Select All. - - CTRL+X, CTRL+C, CTRL+V: Use OS clipboard. - - CTRL+Z, CTRL+Y: Undo, Redo. - - ESCAPE: Revert text to its original value. - - On OSX, controls are automatically adjusted to match standard OSX text editing shortcuts and behaviors. - - - KEYBOARD CONTROLS - - Basic: - - Tab, SHIFT+Tab Cycle through text editable fields. - - CTRL+Tab, CTRL+Shift+Tab Cycle through windows. - - CTRL+Click Input text into a Slider or Drag widget. - - Extended features with `io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard`: - - Tab, SHIFT+Tab: Cycle through every items. - - Arrow keys Move through items using directional navigation. Tweak value. - - Arrow keys + Alt, Shift Tweak slower, tweak faster (when using arrow keys). - - Enter Activate item (prefer text input when possible). - - Space Activate item (prefer tweaking with arrows when possible). - - Escape Deactivate item, leave child window, close popup. - - Page Up, Page Down Previous page, next page. - - Home, End Scroll to top, scroll to bottom. - - Alt Toggle between scrolling layer and menu layer. - - CTRL+Tab then Ctrl+Arrows Move window. Hold SHIFT to resize instead of moving. - - Output when ImGuiConfigFlags_NavEnableKeyboard set, - - io.WantCaptureKeyboard flag is set when keyboard is claimed. - - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. - - io.NavVisible: true when the navigation cursor is visible (usually goes to back false when mouse is used). - - - GAMEPAD CONTROLS - - Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. - - Particularly useful to use Dear ImGui on a console system (e.g. PlayStation, Switch, Xbox) without a mouse! - - Download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets - - Backend support: backend needs to: - - Set 'io.BackendFlags |= ImGuiBackendFlags_HasGamepad' + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys. - - For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly. - Backend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). - - BEFORE 1.87, BACKENDS USED TO WRITE TO io.NavInputs[]. This is now obsolete. Please call io functions instead! - - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing, - with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. - - - REMOTE INPUTS SHARING & MOUSE EMULATION - - PS4/PS5 users: Consider emulating a mouse cursor with DualShock touch pad or a spare analog stick as a mouse-emulation fallback. - - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + run examples/libs/synergy/uSynergy.c (on your console/tablet/phone app) - in order to share your PC mouse/keyboard. - - See https://github.com/ocornut/imgui/wiki/Useful-Extensions#remoting for other remoting solutions. - - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. - Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs Dear ImGui to move your mouse cursor along with navigation movements. - When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. - When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that. - (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, Dear ImGui will misbehave as it will see your mouse moving back & forth!) - (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want - to set a boolean to ignore your other external mouse positions until the external source is moved again.) + - Double-click on title bar to collapse window. + - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin(). + - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents). + - Click and drag on any empty space to move window. + - TAB/SHIFT+TAB to cycle through keyboard editable fields. + - CTRL+Click on a slider or drag box to input value as text. + - Use mouse wheel to scroll. + - Text editor: + - Hold SHIFT or use mouse to select text. + - CTRL+Left/Right to word jump. + - CTRL+Shift+Left/Right to select words. + - CTRL+A or Double-Click to select all. + - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ + - CTRL+Z,CTRL+Y to undo/redo. + - ESCAPE to revert text to its original value. + - Controls are automatically adjusted for OSX to match standard OSX text editing operations. + - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. + - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. Download controller mapping PNG/PSD at http://dearimgui.org/controls_sheets PROGRAMMER GUIDE @@ -193,11 +142,9 @@ CODE READ FIRST ---------- - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki) - - Your code creates the UI every frame of your application loop, if your code doesn't run the UI is gone! - The UI can be highly dynamic, there are no construction or destruction steps, less superfluous - data retention on your side, less state duplication, less state synchronization, fewer bugs. + - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction or + destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, fewer bugs. - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. - Or browse https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html for interactive web version. - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki. @@ -205,38 +152,18 @@ CODE For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI, where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches. - Our origin is on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. + - This codebase is also optimized to yield decent performances with typical "Debug" builds settings. - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected). If you get an assert, read the messages and comments around the assert. - - This codebase aims to be highly optimized: - - A typical idle frame should never call malloc/free. - - We rely on a maximum of constant-time or O(N) algorithms. Limiting searches/scans as much as possible. - - We put particular energy in making sure performances are decent with typical "Debug" build settings as well. - Which mean we tend to avoid over-relying on "zero-cost abstraction" as they aren't zero-cost at all. - - This codebase aims to be both highly opinionated and highly flexible: - - This code works because of the things it choose to solve or not solve. - - C++: this is a pragmatic C-ish codebase: we don't use fancy C++ features, we don't include C++ headers, - and ImGui:: is a namespace. We rarely use member functions (and when we did, I am mostly regretting it now). - This is to increase compatibility, increase maintainability and facilitate use from other languages. - - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. - See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. - We can can optionally export math operators for ImVec2/ImVec4 using IMGUI_DEFINE_MATH_OPERATORS, which we use internally. - - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction - (so don't use ImVector in your code or at our own risk!). - - Building: We don't use nor mandate a build system for the main library. - This is in an effort to ensure that it works in the real world aka with any esoteric build setup. - This is also because providing a build system for the main library would be of little-value. - The build problems are almost never coming from the main library but from specific backends. + - C++: this is a very C-ish codebase: we don't rely on C++11, we don't include any C++ headers, and ImGui:: is a namespace. + - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. + See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. + However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase. + - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!). HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI ---------------------------------------------- - - Update submodule or copy/overwrite every file. - - About imconfig.h: - - You may modify your copy of imconfig.h, in this case don't overwrite it. - - or you may locally branch to modify imconfig.h and merge/rebase latest. - - or you may '#define IMGUI_USER_CONFIG "my_config_file.h"' globally from your build system to - specify a custom path for your imconfig.h file and instead not have to modify the default one. - - Overwrite all the sources files except for imconfig.h (if you have modified your copy of imconfig.h) - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over "master". - You can also use '#define IMGUI_USER_CONFIG "my_config_file.h" to redirect configuration to your own file. @@ -245,12 +172,11 @@ CODE from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will likely be a comment about it. Please report any issue to the GitHub page! - To find out usage of old API, you can add '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in your configuration file. - - Try to keep your copy of Dear ImGui reasonably up to date! + - Try to keep your copy of Dear ImGui reasonably up to date. GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE --------------------------------------------------------------- - - See https://github.com/ocornut/imgui/wiki/Getting-Started. - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. - In the majority of cases you should be able to use unmodified backends files available in the backends/ folder. - Add the Dear ImGui source files + selected backend source files to your projects or using your preferred build system. @@ -314,7 +240,7 @@ CODE // Build and load the texture atlas into a texture // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer) int width, height; - unsigned char* pixels = nullptr; + unsigned char* pixels = NULL; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // At this point you've got the texture data and you need to upload that to your graphic system: @@ -417,6 +343,40 @@ CODE } + USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS + ------------------------------------------ + - The gamepad/keyboard navigation is fairly functional and keeps being improved. + - Gamepad support is particularly useful to use Dear ImGui on a console system (e.g. PlayStation, Switch, Xbox) without a mouse! + - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. + - Keyboard: + - Application: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. + - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), + the io.WantCaptureKeyboard flag will be set. For more advanced uses, you may want to read from: + - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. + - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). + - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions. + Please reach out if you think the game vs navigation input sharing could be improved. + - Gamepad: + - Application: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. + - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys. + For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly. + Backend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). + - BEFORE 1.87, BACKENDS USED TO WRITE TO io.NavInputs[]. This is now obsolete. Please call io functions instead! + - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://dearimgui.org/controls_sheets + - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing, + with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. + - Mouse: + - PS4/PS5 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. + - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard. + - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. + Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. + When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. + When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that. + (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse moving back and forth!) + (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want + to set a boolean to ignore your other external mouse positions until the external source is moved again.) + + API BREAKING CHANGES ==================== @@ -425,47 +385,16 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. - - 2023/07/12 (1.89.8) - ImDrawData: CmdLists now owned, changed from ImDrawList** to ImVector. Majority of users shouldn't be affected, but you cannot compare to NULL nor reassign manually anymore. Instead use AddDrawList(). (#6406, #4879, #1878) - - 2023/06/28 (1.89.7) - overlapping items: obsoleted 'SetItemAllowOverlap()' (called after item) in favor of calling 'SetNextItemAllowOverlap()' (called before item). 'SetItemAllowOverlap()' didn't and couldn't work reliably since 1.89 (2022-11-15). - - 2023/06/28 (1.89.7) - overlapping items: renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete). - - 2023/06/28 (1.89.7) - overlapping items: IsItemHovered() now by default return false when querying an item using AllowOverlap mode which is being overlapped. Use ImGuiHoveredFlags_AllowWhenOverlappedByItem to revert to old behavior. - - 2023/06/28 (1.89.7) - overlapping items: Selectable and TreeNode don't allow overlap when active so overlapping widgets won't appear as hovered. While this fixes a common small visual issue, it also means that calling IsItemHovered() after a non-reactive elements - e.g. Text() - overlapping an active one may fail if you don't use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem). (#6610) - - 2023/06/20 (1.89.7) - moved io.HoverDelayShort/io.HoverDelayNormal to style.HoverDelayShort/style.HoverDelayNormal. As the fields were added in 1.89 and expected to be left unchanged by most users, or only tweaked once during app initialization, we are exceptionally accepting the breakage. - - 2023/05/30 (1.89.6) - backends: renamed "imgui_impl_sdlrenderer.cpp" to "imgui_impl_sdlrenderer2.cpp" and "imgui_impl_sdlrenderer.h" to "imgui_impl_sdlrenderer2.h". This is in prevision for the future release of SDL3. - - 2023/05/22 (1.89.6) - listbox: commented out obsolete/redirecting functions that were marked obsolete more than two years ago: - - ListBoxHeader() -> use BeginListBox() (note how two variants of ListBoxHeader() existed. Check commented versions in imgui.h for reference) - - ListBoxFooter() -> use EndListBox() - - 2023/05/15 (1.89.6) - clipper: commented out obsolete redirection constructor 'ImGuiListClipper(int items_count, float items_height = -1.0f)' that was marked obsolete in 1.79. Use default constructor + clipper.Begin(). - - 2023/05/15 (1.89.6) - clipper: renamed ImGuiListClipper::ForceDisplayRangeByIndices() to ImGuiListClipper::IncludeRangeByIndices(). - - 2023/03/14 (1.89.4) - commented out redirecting enums/functions names that were marked obsolete two years ago: - - ImGuiSliderFlags_ClampOnInput -> use ImGuiSliderFlags_AlwaysClamp - - ImGuiInputTextFlags_AlwaysInsertMode -> use ImGuiInputTextFlags_AlwaysOverwrite - - ImDrawList::AddBezierCurve() -> use ImDrawList::AddBezierCubic() - - ImDrawList::PathBezierCurveTo() -> use ImDrawList::PathBezierCubicCurveTo() - - 2023/03/09 (1.89.4) - renamed PushAllowKeyboardFocus()/PopAllowKeyboardFocus() to PushTabStop()/PopTabStop(). Kept inline redirection functions (will obsolete). - - 2023/03/09 (1.89.4) - tooltips: Added 'bool' return value to BeginTooltip() for API consistency. Please only submit contents and call EndTooltip() if BeginTooltip() returns true. In reality the function will _currently_ always return true, but further changes down the line may change this, best to clarify API sooner. - - 2023/02/15 (1.89.4) - moved the optional "courtesy maths operators" implementation from imgui_internal.h in imgui.h. - Even though we encourage using your own maths types and operators by setting up IM_VEC2_CLASS_EXTRA, - it has been frequently requested by people to use our own. We had an opt-in define which was - previously fulfilled in imgui_internal.h. It is now fulfilled in imgui.h. (#6164) - - OK: #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui.h" / #include "imgui_internal.h" - - Error: #include "imgui.h" / #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui_internal.h" - - 2023/02/07 (1.89.3) - backends: renamed "imgui_impl_sdl.cpp" to "imgui_impl_sdl2.cpp" and "imgui_impl_sdl.h" to "imgui_impl_sdl2.h". (#6146) This is in prevision for the future release of SDL3. - - 2022/10/26 (1.89) - commented out redirecting OpenPopupContextItem() which was briefly the name of OpenPopupOnItemClick() from 1.77 to 1.79. - - 2022/10/12 (1.89) - removed runtime patching of invalid "%f"/"%0.f" format strings for DragInt()/SliderInt(). This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details. - - 2022/09/26 (1.89) - renamed and merged keyboard modifiers key enums and flags into a same set. Kept inline redirection enums (will obsolete). - - ImGuiKey_ModCtrl and ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl - - ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift - - ImGuiKey_ModAlt and ImGuiModFlags_Alt -> ImGuiMod_Alt - - ImGuiKey_ModSuper and ImGuiModFlags_Super -> ImGuiMod_Super - the ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends. - the ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api only by third-party extensions. - exceptionally commenting out the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion and because they were not meant to be used anyway. - - 2022/09/20 (1.89) - ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers. - this will require uses of legacy backend-dependent indices to be casted, e.g. - - with imgui_impl_glfw: IsKeyPressed(GLFW_KEY_A) -> IsKeyPressed((ImGuiKey)GLFW_KEY_A); - - with imgui_impl_win32: IsKeyPressed('A') -> IsKeyPressed((ImGuiKey)'A') - - etc. However if you are upgrading code you might well use the better, backend-agnostic IsKeyPressed(ImGuiKey_A) now! + - 2022/10/26 (1.89) - commented out redirecting OpenPopupContextItem() which was briefly the name of OpenPopupOnItemClick() from 1.77 to 1.79. + - 2022/10/12 (1.89) - removed runtime patching of invalid "%f"/"%0.f" format strings for DragInt()/SliderInt(). This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details. + - 2022/09/26 (1.89) - renamed and merged keyboard modifiers key enums and flags into a same set. Kept inline redirection enums (will obsolete). + - ImGuiKey_ModCtrl and ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl + - ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift + - ImGuiKey_ModAlt and ImGuiModFlags_Alt -> ImGuiMod_Alt + - ImGuiKey_ModSuper and ImGuiModFlags_Super -> ImGuiMod_Super + the ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends. + the ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api only by third-party extensions. + exceptionally commenting out the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion and because they were not meant to be used anyway. - 2022/09/12 (1.89) - removed the bizarre legacy default argument for 'TreePush(const void* ptr = NULL)', always pass a pointer value explicitly. NULL/nullptr is ok but require cast, e.g. TreePush((void*)nullptr); - 2022/09/05 (1.89) - commented out redirecting functions/enums names that were marked obsolete in 1.77 and 1.78 (June 2020): - DragScalar(), DragScalarN(), DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f. @@ -823,7 +752,7 @@ CODE ================================ Read all answers online: - https://www.dearimgui.com/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url) + https://www.dearimgui.org/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url) Read all answers locally (with a text editor or ideally a Markdown viewer): docs/FAQ.md Some answers are copied down here to facilitate searching in code. @@ -833,12 +762,11 @@ CODE Q: Where is the documentation? A: This library is poorly documented at the moment and expects the user to be acquainted with C/C++. - - Run the examples/ applications and explore them. - - Read Getting Started (https://github.com/ocornut/imgui/wiki/Getting-Started) guide. + - Run the examples/ and explore them. - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. - The demo covers most features of Dear ImGui, so you can read the code and see its output. - See documentation and comments at the top of imgui.cpp + effectively imgui.h. - - 20+ standalone example applications using e.g. OpenGL/DirectX are provided in the + - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder to explain how to integrate Dear ImGui with your own engine/application. - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links. - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful. @@ -848,24 +776,24 @@ CODE Q: What is this library called? Q: Which version should I get? >> This library is called "Dear ImGui", please don't call it "ImGui" :) - >> See https://www.dearimgui.com/faq for details. + >> See https://www.dearimgui.org/faq for details. Q&A: Integration ================ Q: How to get started? - A: Read https://github.com/ocornut/imgui/wiki/Getting-Started. Read 'PROGRAMMER GUIDE' above. Read examples/README.txt. + A: Read 'PROGRAMMER GUIDE' above. Read examples/README.txt. Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application? A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! - >> See https://www.dearimgui.com/faq for a fully detailed answer. You really want to read this. + >> See https://www.dearimgui.org/faq for a fully detailed answer. You really want to read this. - Q. How can I enable keyboard or gamepad controls? - Q: How can I use this on a machine without mouse, keyboard or screen? (input share, remote display) + Q. How can I enable keyboard controls? + Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) Q: I integrated Dear ImGui in my engine and little squares are showing instead of text... Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around... Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries... - >> See https://www.dearimgui.com/faq + >> See https://www.dearimgui.org/faq Q&A: Usage ---------- @@ -876,10 +804,10 @@ CODE - How can I have multiple widgets with the same label? - How can I have multiple windows with the same label? Q: How can I display an image? What is ImTextureID, how does it work? - Q: How can I use my own math types instead of ImVec2? + Q: How can I use my own math types instead of ImVec2/ImVec4? Q: How can I interact with standard C++ types (such as std::string and std::vector)? Q: How can I display custom shapes? (using low-level ImDrawList API) - >> See https://www.dearimgui.com/faq + >> See https://www.dearimgui.org/faq Q&A: Fonts, Text ================ @@ -889,7 +817,7 @@ CODE Q: How can I easily use icons in my application? Q: How can I load multiple fonts? Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? - >> See https://www.dearimgui.com/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md + >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md Q&A: Concerns ============= @@ -898,7 +826,7 @@ CODE Q: Can you create elaborate/serious tools with Dear ImGui? Q: Can you reskin the look of Dear ImGui? Q: Why using C++ (as opposed to C)? - >> See https://www.dearimgui.com/faq + >> See https://www.dearimgui.org/faq Q&A: Community ============== @@ -906,10 +834,10 @@ CODE Q: How can I help? A: - Businesses: please reach out to "contact AT dearimgui.com" if you work in a place using Dear ImGui! We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts. - This is among the most useful thing you can do for Dear ImGui. With increased funding, we sustain and grow work on this project. - Also see https://github.com/ocornut/imgui/wiki/Sponsors - - Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine. - - If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, and see how you want to help and can help! + This is among the most useful thing you can do for Dear ImGui. With increased funding, we can hire more people working on this project. + - Individuals: you can support continued development via PayPal donations. See README. + - If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, read docs/TODO.txt + and see how you want to help and can help! - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers. But even without visuals, disclosing your use of dear imgui helps the library grow credibility, and help other teams and programmers with taking decisions. @@ -925,17 +853,21 @@ CODE #define _CRT_SECURE_NO_WARNINGS #endif +#include "imgui.h" +#ifndef IMGUI_DISABLE + #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif - -#include "imgui.h" -#ifndef IMGUI_DISABLE #include "imgui_internal.h" // System includes #include // vsnprintf, sscanf, printf +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else #include // intptr_t +#endif // [Windows] On non-Visual Studio compilers, we default to IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS unless explicitly enabled #if defined(_WIN32) && !defined(_MSC_VER) && !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) @@ -1016,6 +948,7 @@ CODE // Debug options #define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL #define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window +#define IMGUI_DEBUG_INI_SETTINGS 0 // Save additional comments in .ini file (particularly helps for Docking, but makes saving slower) // When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch. static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in @@ -1026,9 +959,6 @@ static const float WINDOWS_HOVER_PADDING = 4.0f; // Exten static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved. -// Tooltip offset -static const ImVec2 TOOLTIP_DEFAULT_OFFSET = ImVec2(16, 10); // Multiplied by g.Style.MouseCursorScale - //------------------------------------------------------------------------- // [SECTION] FORWARD DECLARATIONS //------------------------------------------------------------------------- @@ -1038,6 +968,7 @@ static void FindHoveredWindow(); static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags); static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window); +static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list); static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window); // Settings @@ -1048,8 +979,8 @@ static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSetti static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf); // Platform Dependents default implementation for IO functions -static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx); -static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text); +static const char* GetClipboardTextFn_DefaultImpl(void* user_data); +static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data); namespace ImGui @@ -1068,7 +999,7 @@ static void NavEndFrame(); static bool NavScoreItem(ImGuiNavItemData* result); static void NavApplyItemToResult(ImGuiNavItemData* result); static void NavProcessItem(); -static void NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags); +static void NavProcessItemForTabbingRequest(ImGuiID id); static ImVec2 NavCalcPreferredRefPos(); static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); @@ -1082,20 +1013,18 @@ static void ErrorCheckEndFrameSanityChecks(); static void UpdateDebugToolItemPicker(); static void UpdateDebugToolStackQueries(); -// Inputs +// Misc +static void UpdateSettings(); static void UpdateKeyboardInputs(); static void UpdateMouseInputs(); static void UpdateMouseWheel(); -static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt); - -// Misc -static void UpdateSettings(); static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); static void RenderWindowOuterBorders(ImGuiWindow* window); -static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); +static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col); static void RenderDimmedBackgrounds(); +static ImGuiWindow* FindBlockingModal(ImGuiWindow* window); // Viewports static void UpdateViewportsNewFrame(); @@ -1182,9 +1111,6 @@ ImGuiStyle::ImGuiStyle() ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. - SeparatorTextBorderSize = 3.0f; // Thickkness of border in SeparatorText() - SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). - SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. @@ -1194,13 +1120,6 @@ ImGuiStyle::ImGuiStyle() CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. - // Behaviors - HoverStationaryDelay = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary. - HoverDelayShort = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay. - HoverDelayNormal = 0.40f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). " - HoverFlagsForTooltipMouse = ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse. - HoverFlagsForTooltipNav = ImGuiHoveredFlags_NoSharedDelay | ImGuiHoveredFlags_DelayNormal; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad. - // Default theme ImGui::StyleColorsDark(this); } @@ -1229,7 +1148,6 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor); TabRounding = ImFloor(TabRounding * scale_factor); TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX; - SeparatorTextPadding = ImFloor(SeparatorTextPadding * scale_factor); DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); @@ -1249,10 +1167,16 @@ ImGuiIO::ImGuiIO() IniSavingRate = 5.0f; IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables). LogFilename = "imgui_log.txt"; + MouseDoubleClickTime = 0.30f; + MouseDoubleClickMaxDist = 6.0f; #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO for (int i = 0; i < ImGuiKey_COUNT; i++) KeyMap[i] = -1; #endif + KeyRepeatDelay = 0.275f; + KeyRepeatRate = 0.050f; + HoverDelayNormal = 0.30f; + HoverDelayShort = 0.10f; UserData = NULL; Fonts = NULL; @@ -1261,12 +1185,6 @@ ImGuiIO::ImGuiIO() FontAllowUserScaling = false; DisplayFramebufferScale = ImVec2(1.0f, 1.0f); - MouseDoubleClickTime = 0.30f; - MouseDoubleClickMaxDist = 6.0f; - MouseDragThreshold = 6.0f; - KeyRepeatDelay = 0.275f; - KeyRepeatRate = 0.050f; - // Miscellaneous options MouseDrawCursor = false; #ifdef __APPLE__ @@ -1281,18 +1199,19 @@ ImGuiIO::ImGuiIO() ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; ConfigMemoryCompactTimer = 60.0f; - ConfigDebugBeginReturnValueOnce = false; - ConfigDebugBeginReturnValueLoop = false; // Platform Functions - // Note: Initialize() will setup default clipboard/ime handlers. BackendPlatformName = BackendRendererName = NULL; BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; + GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations + SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; + ClipboardUserData = NULL; + SetPlatformImeDataFn = SetPlatformImeDataFn_DefaultImpl; // Input (NB: we already have memset zero the entire structure!) MousePos = ImVec2(-FLT_MAX, -FLT_MAX); MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX); - MouseSource = ImGuiMouseSource_Mouse; + MouseDragThreshold = 6.0f; for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; } AppAcceptingEvents = true; @@ -1306,15 +1225,14 @@ ImGuiIO::ImGuiIO() // FIXME: Should in theory be called "AddCharacterEvent()" to be consistent with new API void ImGuiIO::AddInputCharacter(unsigned int c) { - IM_ASSERT(Ctx != NULL); - ImGuiContext& g = *Ctx; + ImGuiContext& g = *GImGui; + IM_ASSERT(&g.IO == this && "Can only add events to current context."); if (c == 0 || !AppAcceptingEvents) return; ImGuiInputEvent e; e.Type = ImGuiInputEventType_Text; e.Source = ImGuiInputSource_Keyboard; - e.EventId = g.InputEventsNextEventId++; e.Text.Char = c; g.InputEventsQueue.push_back(e); } @@ -1363,19 +1281,18 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) { unsigned int c = 0; utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); - AddInputCharacter(c); + if (c != 0) + AddInputCharacter(c); } } -// Clear all incoming events. -void ImGuiIO::ClearEventsQueue() +// FIXME: Perhaps we could clear queued events as well? +void ImGuiIO::ClearInputCharacters() { - IM_ASSERT(Ctx != NULL); - ImGuiContext& g = *Ctx; - g.InputEventsQueue.clear(); + InputQueueCharacters.resize(0); } -// Clear current keyboard/mouse/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons. +// FIXME: Perhaps we could clear queued events as well? void ImGuiIO::ClearInputKeys() { #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO @@ -1396,21 +1313,11 @@ void ImGuiIO::ClearInputKeys() MouseDownDuration[n] = MouseDownDurationPrev[n] = -1.0f; } MouseWheel = MouseWheelH = 0.0f; - InputQueueCharacters.resize(0); // Behavior of old ClearInputCharacters(). } -// Removed this as it is ambiguous/misleading and generally incorrect to use with the existence of a higher-level input queue. -// Current frame character buffer is now also cleared by ClearInputKeys(). -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -void ImGuiIO::ClearInputCharacters() -{ - InputQueueCharacters.resize(0); -} -#endif - -static ImGuiInputEvent* FindLatestInputEvent(ImGuiContext* ctx, ImGuiInputEventType type, int arg = -1) +static ImGuiInputEvent* FindLatestInputEvent(ImGuiInputEventType type, int arg = -1) { - ImGuiContext& g = *ctx; + ImGuiContext& g = *GImGui; for (int n = g.InputEventsQueue.Size - 1; n >= 0; n--) { ImGuiInputEvent* e = &g.InputEventsQueue[n]; @@ -1429,18 +1336,15 @@ static ImGuiInputEvent* FindLatestInputEvent(ImGuiContext* ctx, ImGuiInputEventT // - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character) // - bool down: Is the key down? use false to signify a key release. // - float analog_value: 0.0f..1.0f -// IMPORTANT: THIS FUNCTION AND OTHER "ADD" GRABS THE CONTEXT FROM OUR INSTANCE. -// WE NEED TO ENSURE THAT ALL FUNCTION CALLS ARE FULLFILLING THIS, WHICH IS WHY GetKeyData() HAS AN EXPLICIT CONTEXT. void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) { //if (e->Down) { IMGUI_DEBUG_LOG_IO("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); } - IM_ASSERT(Ctx != NULL); if (key == ImGuiKey_None || !AppAcceptingEvents) return; - ImGuiContext& g = *Ctx; + ImGuiContext& g = *GImGui; + IM_ASSERT(&g.IO == this && "Can only add events to current context."); IM_ASSERT(ImGui::IsNamedKeyOrModKey(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API. - IM_ASSERT(ImGui::IsAliasKey(key) == false); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events. - IM_ASSERT(key != ImGuiMod_Shortcut); // We could easily support the translation here but it seems saner to not accept it (TestEngine perform a translation itself) + IM_ASSERT(!ImGui::IsAliasKey(key)); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events. // Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data. #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO @@ -1454,8 +1358,8 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) BackendUsingLegacyNavInputArray = false; // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed) - const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key); - const ImGuiKeyData* key_data = ImGui::GetKeyData(&g, key); + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Key, (int)key); + const ImGuiKeyData* key_data = ImGui::GetKeyData(key); const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down; const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue; if (latest_key_down == down && latest_key_analog == analog_value) @@ -1465,7 +1369,6 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) ImGuiInputEvent e; e.Type = ImGuiInputEventType_Key; e.Source = ImGui::IsGamepadKey(key) ? ImGuiInputSource_Gamepad : ImGuiInputSource_Keyboard; - e.EventId = g.InputEventsNextEventId++; e.Key.Key = key; e.Key.Down = down; e.Key.AnalogValue = analog_value; @@ -1513,8 +1416,8 @@ void ImGuiIO::SetAppAcceptingEvents(bool accepting_events) // Queue a mouse move event void ImGuiIO::AddMousePosEvent(float x, float y) { - IM_ASSERT(Ctx != NULL); - ImGuiContext& g = *Ctx; + ImGuiContext& g = *GImGui; + IM_ASSERT(&g.IO == this && "Can only add events to current context."); if (!AppAcceptingEvents) return; @@ -1522,7 +1425,7 @@ void ImGuiIO::AddMousePosEvent(float x, float y) ImVec2 pos((x > -FLT_MAX) ? ImFloorSigned(x) : x, (y > -FLT_MAX) ? ImFloorSigned(y) : y); // Filter duplicate - const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MousePos); + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MousePos); const ImVec2 latest_pos = latest_event ? ImVec2(latest_event->MousePos.PosX, latest_event->MousePos.PosY) : g.IO.MousePos; if (latest_pos.x == pos.x && latest_pos.y == pos.y) return; @@ -1530,23 +1433,21 @@ void ImGuiIO::AddMousePosEvent(float x, float y) ImGuiInputEvent e; e.Type = ImGuiInputEventType_MousePos; e.Source = ImGuiInputSource_Mouse; - e.EventId = g.InputEventsNextEventId++; e.MousePos.PosX = pos.x; e.MousePos.PosY = pos.y; - e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; g.InputEventsQueue.push_back(e); } void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down) { - IM_ASSERT(Ctx != NULL); - ImGuiContext& g = *Ctx; + ImGuiContext& g = *GImGui; + IM_ASSERT(&g.IO == this && "Can only add events to current context."); IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT); if (!AppAcceptingEvents) return; // Filter duplicate - const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MouseButton, (int)mouse_button); + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MouseButton, (int)mouse_button); const bool latest_button_down = latest_event ? latest_event->MouseButton.Down : g.IO.MouseDown[mouse_button]; if (latest_button_down == down) return; @@ -1554,18 +1455,16 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down) ImGuiInputEvent e; e.Type = ImGuiInputEventType_MouseButton; e.Source = ImGuiInputSource_Mouse; - e.EventId = g.InputEventsNextEventId++; e.MouseButton.Button = mouse_button; e.MouseButton.Down = down; - e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; g.InputEventsQueue.push_back(e); } -// Queue a mouse wheel event (some mouse/API may only have a Y component) +// Queue a mouse wheel event (most mouse/API will only have a Y component) void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y) { - IM_ASSERT(Ctx != NULL); - ImGuiContext& g = *Ctx; + ImGuiContext& g = *GImGui; + IM_ASSERT(&g.IO == this && "Can only add events to current context."); // Filter duplicate (unlike most events, wheel values are relative and easy to filter) if (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f)) @@ -1574,36 +1473,24 @@ void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y) ImGuiInputEvent e; e.Type = ImGuiInputEventType_MouseWheel; e.Source = ImGuiInputSource_Mouse; - e.EventId = g.InputEventsNextEventId++; e.MouseWheel.WheelX = wheel_x; e.MouseWheel.WheelY = wheel_y; - e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; g.InputEventsQueue.push_back(e); } -// This is not a real event, the data is latched in order to be stored in actual Mouse events. -// This is so that duplicate events (e.g. Windows sending extraneous WM_MOUSEMOVE) gets filtered and are not leading to actual source changes. -void ImGuiIO::AddMouseSourceEvent(ImGuiMouseSource source) -{ - IM_ASSERT(Ctx != NULL); - ImGuiContext& g = *Ctx; - g.InputEventsNextMouseSource = source; -} - void ImGuiIO::AddFocusEvent(bool focused) { - IM_ASSERT(Ctx != NULL); - ImGuiContext& g = *Ctx; + ImGuiContext& g = *GImGui; + IM_ASSERT(&g.IO == this && "Can only add events to current context."); // Filter duplicate - const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Focus); + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Focus); const bool latest_focused = latest_event ? latest_event->AppFocused.Focused : !g.IO.AppFocusLost; - if (latest_focused == focused || (ConfigDebugIgnoreFocusLoss && !focused)) + if (latest_focused == focused) return; ImGuiInputEvent e; e.Type = ImGuiInputEventType_Focus; - e.EventId = g.InputEventsNextEventId++; e.AppFocused.Focused = focused; g.InputEventsQueue.push_back(e); } @@ -1860,15 +1747,13 @@ const char* ImStrSkipBlank(const char* str) // and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are // designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.) #ifdef IMGUI_USE_STB_SPRINTF -#ifndef IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION -#endif #ifdef IMGUI_STB_SPRINTF_FILENAME #include IMGUI_STB_SPRINTF_FILENAME #else #include "stb_sprintf.h" #endif -#endif // #ifdef IMGUI_USE_STB_SPRINTF +#endif #if defined(_MSC_VER) && !defined(vsnprintf) #define vsnprintf _vsnprintf @@ -1913,36 +1798,18 @@ void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end, ImGuiContext& g = *GImGui; va_list args; va_start(args, fmt); - if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) - { - const char* buf = va_arg(args, const char*); // Skip formatting when using "%s" - *out_buf = buf; - if (out_buf_end) { *out_buf_end = buf + strlen(buf); } - } - else - { - int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); - *out_buf = g.TempBuffer.Data; - if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; } - } + int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); + *out_buf = g.TempBuffer.Data; + if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; } va_end(args); } void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args) { ImGuiContext& g = *GImGui; - if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) - { - const char* buf = va_arg(args, const char*); // Skip formatting when using "%s" - *out_buf = buf; - if (out_buf_end) { *out_buf_end = buf + strlen(buf); } - } - else - { - int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); - *out_buf = g.TempBuffer.Data; - if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; } - } + int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); + *out_buf = g.TempBuffer.Data; + if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; } } // CRC32 needs a 1KB lookup table (not cache friendly) @@ -1971,7 +1838,7 @@ static const ImU32 GCrc32LookupTable[256] = // Known size hash // It is ok to call ImHashData on a string with known length but the ### operator won't be supported. // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. -ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed) +ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed) { ImU32 crc = ~seed; const unsigned char* data = (const unsigned char*)data_p; @@ -1987,7 +1854,7 @@ ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed) // - If we reach ### in the string we discard the hash so far and reset to the seed. // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build) // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. -ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) +ImGuiID ImHashStr(const char* data_p, size_t data_size, ImU32 seed) { seed = ~seed; ImU32 crc = seed; @@ -2029,7 +1896,7 @@ ImFileHandle ImFileOpen(const char* filename, const char* mode) // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); - ImVector buf; + ImVector buf; buf.resize(filename_wsize + mode_wsize); ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize); ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize); @@ -2092,8 +1959,6 @@ void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_f // [SECTION] MISC HELPERS/UTILITIES (ImText* functions) //----------------------------------------------------------------------------- -IM_MSVC_RUNTIME_CHECKS_OFF - // Convert UTF-8 to 32-bit character, process single character input. // A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8). // We handle UTF-8 decoding error by skipping forward. @@ -2105,7 +1970,7 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* static const int shiftc[] = { 0, 18, 12, 6, 0 }; static const int shifte[] = { 0, 6, 4, 2, 0 }; int len = lengths[*(const unsigned char*)in_text >> 3]; - int wanted = len + (len ? 0 : 1); + int wanted = len + !len; if (in_text_end == NULL) in_text_end = in_text + wanted; // Max length, nulls will be taken into account. @@ -2157,6 +2022,8 @@ int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const cha { unsigned int c; in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + if (c == 0) + break; *buf_out++ = (ImWchar)c; } *buf_out = 0; @@ -2172,6 +2039,8 @@ int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end) { unsigned int c; in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + if (c == 0) + break; char_count++; } return char_count; @@ -2265,7 +2134,6 @@ int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_e } return bytes_count; } -IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- // [SECTION] MISC HELPERS/UTILITIES (Color functions) @@ -2805,6 +2673,7 @@ static void ImGuiListClipper_SeekCursorForItem(ImGuiListClipper* clipper, int it ImGuiListClipper::ImGuiListClipper() { memset(this, 0, sizeof(*this)); + ItemsCount = -1; } ImGuiListClipper::~ImGuiListClipper() @@ -2814,10 +2683,7 @@ ImGuiListClipper::~ImGuiListClipper() void ImGuiListClipper::Begin(int items_count, float items_height) { - if (Ctx == NULL) - Ctx = ImGui::GetCurrentContext(); - - ImGuiContext& g = *Ctx; + ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; IMGUI_DEBUG_LOG_CLIPPER("Clipper: Begin(%d,%.2f) in '%s'\n", items_count, items_height, window->Name); @@ -2842,10 +2708,10 @@ void ImGuiListClipper::Begin(int items_count, float items_height) void ImGuiListClipper::End() { + ImGuiContext& g = *GImGui; if (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData) { // In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user. - ImGuiContext& g = *Ctx; IMGUI_DEBUG_LOG_CLIPPER("Clipper: End() in '%s'\n", g.CurrentWindow->Name); if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0) ImGuiListClipper_SeekCursorForItem(this, ItemsCount); @@ -2863,18 +2729,18 @@ void ImGuiListClipper::End() ItemsCount = -1; } -void ImGuiListClipper::IncludeRangeByIndices(int item_begin, int item_end) +void ImGuiListClipper::ForceDisplayRangeByIndices(int item_min, int item_max) { ImGuiListClipperData* data = (ImGuiListClipperData*)TempData; IM_ASSERT(DisplayStart < 0); // Only allowed after Begin() and if there has not been a specified range yet. - IM_ASSERT(item_begin <= item_end); - if (item_begin < item_end) - data->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_begin, item_end)); + IM_ASSERT(item_min <= item_max); + if (item_min < item_max) + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_min, item_max)); } static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) { - ImGuiContext& g = *clipper->Ctx; + ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData; IM_ASSERT(data != NULL && "Called ImGuiListClipper::Step() too many times, or before ImGuiListClipper::Begin() ?"); @@ -2946,7 +2812,7 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); if (is_nav_request) data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, 0, 0)); - if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && g.NavTabbingDir == -1) + if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && g.NavTabbingDir == -1) data->Ranges.push_back(ImGuiListClipperRange::FromIndices(clipper->ItemsCount - 1, clipper->ItemsCount)); // Add focused/active item @@ -2997,7 +2863,7 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) bool ImGuiListClipper::Step() { - ImGuiContext& g = *Ctx; + ImGuiContext& g = *GImGui; bool need_items_height = (ItemsHeight <= 0.0f); bool ret = ImGuiListClipper_StepInternal(this); if (ret && (DisplayStart == DisplayEnd)) @@ -3007,14 +2873,11 @@ bool ImGuiListClipper::Step() if (need_items_height && ItemsHeight > 0.0f) IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): computed ItemsHeight: %.2f.\n", ItemsHeight); if (ret) - { IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): display %d to %d.\n", DisplayStart, DisplayEnd); - } else - { IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): End.\n"); + if (!ret) End(); - } return ret; } @@ -3098,7 +2961,15 @@ void ImGui::PopStyleColor(int count) } } -static const ImGuiDataVarInfo GStyleVarInfo[] = +struct ImGuiStyleVarInfo +{ + ImGuiDataType Type; + ImU32 Count; + ImU32 Offset; + void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); } +}; + +static const ImGuiStyleVarInfo GStyleVarInfo[] = { { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha @@ -3125,44 +2996,41 @@ static const ImGuiDataVarInfo GStyleVarInfo[] = { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign - { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextBorderSize) },// ImGuiStyleVar_SeparatorTextBorderSize - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign - { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding }; -const ImGuiDataVarInfo* ImGui::GetStyleVarInfo(ImGuiStyleVar idx) +static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) { IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); - IM_STATIC_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); + IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); return &GStyleVarInfo[idx]; } void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { - ImGuiContext& g = *GImGui; - const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) { + ImGuiContext& g = *GImGui; float* pvar = (float*)var_info->GetVarPtr(&g.Style); g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; return; } - IM_ASSERT_USER_ERROR(0, "Called PushStyleVar() variant with wrong type!"); + IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!"); } void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { - ImGuiContext& g = *GImGui; - const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) { + ImGuiContext& g = *GImGui; ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; return; } - IM_ASSERT_USER_ERROR(0, "Called PushStyleVar() variant with wrong type!"); + IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!"); } void ImGui::PopStyleVar(int count) @@ -3177,7 +3045,7 @@ void ImGui::PopStyleVar(int count) { // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. ImGuiStyleMod& backup = g.StyleVarStack.back(); - const ImGuiDataVarInfo* info = GetStyleVarInfo(backup.VarIdx); + const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); void* data = info->GetVarPtr(&g.Style); if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } @@ -3314,9 +3182,6 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end // Default clip_rect uses (pos_min,pos_max) // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) -// FIXME-OPT: Since we have or calculate text_size we could coarse clip whole block immediately, especally for text above draw_list->DrawList. -// Effectively as this is called from widget doing their own coarse clipping it's not very valuable presently. Next time function will take -// better advantage of the render function taking size into account for coarse clipping. void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) { // Perform CPU side clipping for single clipped element to avoid using scissor state @@ -3360,6 +3225,7 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons LogRenderedText(&pos_min, text, text_display_end); } + // Another overly complex function until we reorganize everything into a nice all-in-one helper. // This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display. // This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. @@ -3383,12 +3249,30 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con const ImFont* font = draw_list->_Data->Font; const float font_size = draw_list->_Data->FontSize; - const float font_scale = font_size / font->FontSize; const char* text_end_ellipsis = NULL; - const float ellipsis_width = font->EllipsisWidth * font_scale; + + ImWchar ellipsis_char = font->EllipsisChar; + int ellipsis_char_count = 1; + if (ellipsis_char == (ImWchar)-1) + { + ellipsis_char = font->DotChar; + ellipsis_char_count = 3; + } + const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char); + + float ellipsis_glyph_width = glyph->X1; // Width of the glyph with no padding on either side + float ellipsis_total_width = ellipsis_glyph_width; // Full width of entire ellipsis + + if (ellipsis_char_count > 1) + { + // Full ellipsis size without free spacing after it. + const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize); + ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots; + ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots; + } // We can now claim the space between pos_max.x and ellipsis_max.x - const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f); + const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f); float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x; if (text == text_end_ellipsis && text_end_ellipsis < text_end_full) { @@ -3405,10 +3289,13 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con // Render text, render ellipsis RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); - ImVec2 ellipsis_pos = ImFloor(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y)); - if (ellipsis_pos.x + ellipsis_width <= ellipsis_max_x) - for (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale) - font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar); + float ellipsis_x = pos_min.x + text_size_clipped_x; + if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x) + for (int i = 0; i < ellipsis_char_count; i++) + { + font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char); + ellipsis_x += ellipsis_glyph_width; + } } else { @@ -3481,391 +3368,157 @@ void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCurso { ImGuiContext& g = *GImGui; IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); - ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas; for (int n = 0; n < g.Viewports.Size; n++) { - // We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor. - ImVec2 offset, size, uv[4]; - if (!font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) - continue; ImGuiViewportP* viewport = g.Viewports[n]; - const ImVec2 pos = base_pos - offset; - const float scale = base_scale; - if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale))) - continue; ImDrawList* draw_list = GetForegroundDrawList(viewport); - ImTextureID tex_id = font_atlas->TexID; - draw_list->PushTextureID(tex_id); - draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow); - draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow); - draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border); - draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill); - draw_list->PopTextureID(); + ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas; + ImVec2 offset, size, uv[4]; + if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) + { + const ImVec2 pos = base_pos - offset; + const float scale = base_scale; + ImTextureID tex_id = font_atlas->TexID; + draw_list->PushTextureID(tex_id); + draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border); + draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill); + draw_list->PopTextureID(); + } } } + //----------------------------------------------------------------------------- -// [SECTION] INITIALIZATION, SHUTDOWN +// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) //----------------------------------------------------------------------------- -// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself -// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module -ImGuiContext* ImGui::GetCurrentContext() +// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods +ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst(NULL) { - return GImGui; + memset(this, 0, sizeof(*this)); + Name = ImStrdup(name); + NameBufLen = (int)strlen(name) + 1; + ID = ImHashStr(name); + IDStack.push_back(ID); + MoveId = GetID("#MOVE"); + ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); + AutoFitFramesX = AutoFitFramesY = -1; + AutoPosLastDirection = ImGuiDir_None; + SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; + SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); + LastFrameActive = -1; + LastTimeActive = -1.0f; + FontWindowScale = 1.0f; + SettingsOffset = -1; + DrawList = &DrawListInst; + DrawList->_Data = &context->DrawListSharedData; + DrawList->_OwnerName = Name; } -void ImGui::SetCurrentContext(ImGuiContext* ctx) +ImGuiWindow::~ImGuiWindow() { -#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC - IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this. -#else - GImGui = ctx; -#endif + IM_ASSERT(DrawList == &DrawListInst); + IM_DELETE(Name); + ColumnsStorage.clear_destruct(); } -void ImGui::SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data) +ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) { - GImAllocatorAllocFunc = alloc_func; - GImAllocatorFreeFunc = free_func; - GImAllocatorUserData = user_data; + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end); + return id; } -// This is provided to facilitate copying allocators from one static/DLL boundary to another (e.g. retrieve default allocator of your executable address space) -void ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data) +ImGuiID ImGuiWindow::GetID(const void* ptr) { - *p_alloc_func = GImAllocatorAllocFunc; - *p_free_func = GImAllocatorFreeFunc; - *p_user_data = GImAllocatorUserData; + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL); + return id; } -ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) +ImGuiID ImGuiWindow::GetID(int n) { - ImGuiContext* prev_ctx = GetCurrentContext(); - ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); - SetCurrentContext(ctx); - Initialize(); - if (prev_ctx != NULL) - SetCurrentContext(prev_ctx); // Restore previous context if any, else keep new one. - return ctx; + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&n, sizeof(n), seed); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL); + return id; } -void ImGui::DestroyContext(ImGuiContext* ctx) +// This is only used in rare/specific situations to manufacture an ID out of nowhere. +ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) { - ImGuiContext* prev_ctx = GetCurrentContext(); - if (ctx == NULL) //-V1051 - ctx = prev_ctx; - SetCurrentContext(ctx); - Shutdown(); - SetCurrentContext((prev_ctx != ctx) ? prev_ctx : NULL); - IM_DELETE(ctx); + ImGuiID seed = IDStack.back(); + ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs); + ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); + return id; } -// IMPORTANT: ###xxx suffixes must be same in ALL languages -static const ImGuiLocEntry GLocalizationEntriesEnUS[] = +static void SetCurrentWindow(ImGuiWindow* window) { - { ImGuiLocKey_VersionStr, "Dear ImGui " IMGUI_VERSION " (" IM_STRINGIFY(IMGUI_VERSION_NUM) ")" }, - { ImGuiLocKey_TableSizeOne, "Size column to fit###SizeOne" }, - { ImGuiLocKey_TableSizeAllFit, "Size all columns to fit###SizeAll" }, - { ImGuiLocKey_TableSizeAllDefault, "Size all columns to default###SizeAll" }, - { ImGuiLocKey_TableResetOrder, "Reset order###ResetOrder" }, - { ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" }, - { ImGuiLocKey_WindowingPopup, "(Popup)" }, - { ImGuiLocKey_WindowingUntitled, "(Untitled)" }, -}; + ImGuiContext& g = *GImGui; + g.CurrentWindow = window; + g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL; + if (window) + g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); +} -void ImGui::Initialize() +void ImGui::GcCompactTransientMiscBuffers() { ImGuiContext& g = *GImGui; - IM_ASSERT(!g.Initialized && !g.SettingsLoaded); + g.ItemFlagsStack.clear(); + g.GroupStack.clear(); + TableGcCompactSettings(); +} - // Add .ini handle for ImGuiWindow and ImGuiTable types - { - ImGuiSettingsHandler ini_handler; - ini_handler.TypeName = "Window"; - ini_handler.TypeHash = ImHashStr("Window"); - ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll; - ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen; - ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine; - ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll; - ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll; - AddSettingsHandler(&ini_handler); - } - TableSettingsAddSettingsHandler(); +// Free up/compact internal window buffers, we can use this when a window becomes unused. +// Not freed: +// - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data) +// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost. +void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window) +{ + window->MemoryCompacted = true; + window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity; + window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity; + window->IDStack.clear(); + window->DrawList->_ClearFreeMemory(); + window->DC.ChildWindows.clear(); + window->DC.ItemWidthStack.clear(); + window->DC.TextWrapPosStack.clear(); +} - // Setup default localization table - LocalizeRegisterEntries(GLocalizationEntriesEnUS, IM_ARRAYSIZE(GLocalizationEntriesEnUS)); +void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window) +{ + // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening. + // The other buffers tends to amortize much faster. + window->MemoryCompacted = false; + window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity); + window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity); + window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0; +} - // Setup default platform clipboard/IME handlers. - g.IO.GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations - g.IO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; - g.IO.ClipboardUserData = (void*)&g; // Default implementation use the ImGuiContext as user data (ideally those would be arguments to the function) - g.IO.SetPlatformImeDataFn = SetPlatformImeDataFn_DefaultImpl; +void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; - // Create default viewport - ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(); - g.Viewports.push_back(viewport); - g.TempBuffer.resize(1024 * 3 + 1, 0); - -#ifdef IMGUI_HAS_DOCK -#endif - - g.Initialized = true; -} - -// This function is merely here to free heap allocations. -void ImGui::Shutdown() -{ - // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) - ImGuiContext& g = *GImGui; - if (g.IO.Fonts && g.FontAtlasOwnedByContext) - { - g.IO.Fonts->Locked = false; - IM_DELETE(g.IO.Fonts); - } - g.IO.Fonts = NULL; - g.DrawListSharedData.TempBuffer.clear(); - - // Cleanup of other data are conditional on actually having initialized Dear ImGui. - if (!g.Initialized) - return; - - // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file) - if (g.SettingsLoaded && g.IO.IniFilename != NULL) - SaveIniSettingsToDisk(g.IO.IniFilename); - - CallContextHooks(&g, ImGuiContextHookType_Shutdown); - - // Clear everything else - g.Windows.clear_delete(); - g.WindowsFocusOrder.clear(); - g.WindowsTempSortBuffer.clear(); - g.CurrentWindow = NULL; - g.CurrentWindowStack.clear(); - g.WindowsById.Clear(); - g.NavWindow = NULL; - g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; - g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; - g.MovingWindow = NULL; - - g.KeysRoutingTable.Clear(); - - g.ColorStack.clear(); - g.StyleVarStack.clear(); - g.FontStack.clear(); - g.OpenPopupStack.clear(); - g.BeginPopupStack.clear(); - - g.Viewports.clear_delete(); - - g.TabBars.Clear(); - g.CurrentTabBarStack.clear(); - g.ShrinkWidthBuffer.clear(); - - g.ClipperTempData.clear_destruct(); - - g.Tables.Clear(); - g.TablesTempData.clear_destruct(); - g.DrawChannelsTempMergeBuffer.clear(); - - g.ClipboardHandlerData.clear(); - g.MenusIdSubmittedThisFrame.clear(); - g.InputTextState.ClearFreeMemory(); - g.InputTextDeactivatedState.ClearFreeMemory(); - - g.SettingsWindows.clear(); - g.SettingsHandlers.clear(); - - if (g.LogFile) - { -#ifndef IMGUI_DISABLE_TTY_FUNCTIONS - if (g.LogFile != stdout) -#endif - ImFileClose(g.LogFile); - g.LogFile = NULL; - } - g.LogBuffer.clear(); - g.DebugLogBuf.clear(); - g.DebugLogIndex.clear(); - - g.Initialized = false; -} - -// No specific ordering/dependency support, will see as needed -ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook) -{ - ImGuiContext& g = *ctx; - IM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_); - g.Hooks.push_back(*hook); - g.Hooks.back().HookId = ++g.HookIdNext; - return g.HookIdNext; -} - -// Deferred removal, avoiding issue with changing vector while iterating it -void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id) -{ - ImGuiContext& g = *ctx; - IM_ASSERT(hook_id != 0); - for (int n = 0; n < g.Hooks.Size; n++) - if (g.Hooks[n].HookId == hook_id) - g.Hooks[n].Type = ImGuiContextHookType_PendingRemoval_; -} - -// Call context hooks (used by e.g. test engine) -// We assume a small number of hooks so all stored in same array -void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type) -{ - ImGuiContext& g = *ctx; - for (int n = 0; n < g.Hooks.Size; n++) - if (g.Hooks[n].Type == hook_type) - g.Hooks[n].Callback(&g, &g.Hooks[n]); -} - - -//----------------------------------------------------------------------------- -// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) -//----------------------------------------------------------------------------- - -// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods -ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NULL) -{ - memset(this, 0, sizeof(*this)); - Ctx = ctx; - Name = ImStrdup(name); - NameBufLen = (int)strlen(name) + 1; - ID = ImHashStr(name); - IDStack.push_back(ID); - MoveId = GetID("#MOVE"); - ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); - ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); - AutoFitFramesX = AutoFitFramesY = -1; - AutoPosLastDirection = ImGuiDir_None; - SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = 0; - SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); - LastFrameActive = -1; - LastTimeActive = -1.0f; - FontWindowScale = 1.0f; - SettingsOffset = -1; - DrawList = &DrawListInst; - DrawList->_Data = &Ctx->DrawListSharedData; - DrawList->_OwnerName = Name; - NavPreferredScoringPosRel[0] = NavPreferredScoringPosRel[1] = ImVec2(FLT_MAX, FLT_MAX); -} - -ImGuiWindow::~ImGuiWindow() -{ - IM_ASSERT(DrawList == &DrawListInst); - IM_DELETE(Name); - ColumnsStorage.clear_destruct(); -} - -ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) -{ - ImGuiID seed = IDStack.back(); - ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); - ImGuiContext& g = *Ctx; - if (g.DebugHookIdInfo == id) - ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end); - return id; -} - -ImGuiID ImGuiWindow::GetID(const void* ptr) -{ - ImGuiID seed = IDStack.back(); - ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); - ImGuiContext& g = *Ctx; - if (g.DebugHookIdInfo == id) - ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL); - return id; -} - -ImGuiID ImGuiWindow::GetID(int n) -{ - ImGuiID seed = IDStack.back(); - ImGuiID id = ImHashData(&n, sizeof(n), seed); - ImGuiContext& g = *Ctx; - if (g.DebugHookIdInfo == id) - ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL); - return id; -} - -// This is only used in rare/specific situations to manufacture an ID out of nowhere. -ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) -{ - ImGuiID seed = IDStack.back(); - ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs); - ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); - return id; -} - -static void SetCurrentWindow(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - g.CurrentWindow = window; - g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL; - if (window) - { - g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); - ImGui::NavUpdateCurrentWindowIsScrollPushableX(); - } -} - -void ImGui::GcCompactTransientMiscBuffers() -{ - ImGuiContext& g = *GImGui; - g.ItemFlagsStack.clear(); - g.GroupStack.clear(); - TableGcCompactSettings(); -} - -// Free up/compact internal window buffers, we can use this when a window becomes unused. -// Not freed: -// - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data) -// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost. -void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window) -{ - window->MemoryCompacted = true; - window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity; - window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity; - window->IDStack.clear(); - window->DrawList->_ClearFreeMemory(); - window->DC.ChildWindows.clear(); - window->DC.ItemWidthStack.clear(); - window->DC.TextWrapPosStack.clear(); -} - -void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window) -{ - // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening. - // The other buffers tends to amortize much faster. - window->MemoryCompacted = false; - window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity); - window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity); - window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0; -} - -void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - - // Clear previous active id - if (g.ActiveId != 0) - { - // While most behaved code would make an effort to not steal active id during window move/drag operations, - // we at least need to be resilient to it. Canceling the move is rather aggressive and users of 'master' branch - // may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that. - if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId) - { - IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n"); - g.MovingWindow = NULL; - } - - // This could be written in a more general way (e.g associate a hook to ActiveId), - // but since this is currently quite an exception we'll leave it as is. - // One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveId() - if (g.InputTextState.ID == g.ActiveId) - InputTextDeactivateHook(g.ActiveId); - } + // While most behaved code would make an effort to not steal active id during window move/drag operations, + // we at least need to be resilient to it. Cancelling the move is rather aggressive and users of 'master' branch + // may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that. + if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId) + { + IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n"); + g.MovingWindow = NULL; + } // Set active id g.ActiveIdIsJustActivated = (g.ActiveId != id); @@ -3890,8 +3543,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) if (id) { g.ActiveIdIsAlive = id; - g.ActiveIdSource = (g.NavActivateId == id || g.NavJustMovedToId == id) ? g.NavInputSource : ImGuiInputSource_Mouse; - IM_ASSERT(g.ActiveIdSource != ImGuiInputSource_None); + g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustMovedToId == id) ? (ImGuiInputSource)ImGuiInputSource_Nav : ImGuiInputSource_Mouse; } // Clear declaration of inputs claimed by the widget @@ -3939,21 +3591,15 @@ void ImGui::MarkItemEdited(ImGuiID id) // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data. ImGuiContext& g = *GImGui; - if (g.ActiveId == id || g.ActiveId == 0) - { - g.ActiveIdHasBeenEditedThisFrame = true; - g.ActiveIdHasBeenEditedBefore = true; - } - - // We accept a MarkItemEdited() on drag and drop targets (see https://github.com/ocornut/imgui/issues/1875#issuecomment-978243343) - // We accept 'ActiveIdPreviousFrame == id' for InputText() returning an edit after it has been taken ActiveId away (#4714) - IM_ASSERT(g.DragDropActive || g.ActiveId == id || g.ActiveId == 0 || g.ActiveIdPreviousFrame == id); - + IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); + IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out. //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); + g.ActiveIdHasBeenEditedThisFrame = true; + g.ActiveIdHasBeenEditedBefore = true; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited; } -bool ImGui::IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) +static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) { // An active popup disable hovering on other windows (apart from its own children) // FIXME-OPT: This could be cached/stored within the window. @@ -3972,22 +3618,12 @@ bool ImGui::IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flag // Inhibit hover unless the window is within the stack of our modal/popup if (want_inhibit) - if (!IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window)) + if (!ImGui::IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window)) return false; } return true; } -static inline float CalcDelayFromHoveredFlags(ImGuiHoveredFlags flags) -{ - ImGuiContext& g = *GImGui; - if (flags & ImGuiHoveredFlags_DelayShort) - return g.Style.HoverDelayShort; - if (flags & ImGuiHoveredFlags_DelayNormal) - return g.Style.HoverDelayNormal; - return 0.0f; -} - // This is roughly matching the behavior of internal-facing ItemHoverable() // - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered() // - this should work even for non-interactive items that have no ID, so we cannot use LastItemId @@ -3995,17 +3631,12 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT((flags & ~ImGuiHoveredFlags_AllowedMaskForIsItemHovered) == 0 && "Invalid flags for IsItemHovered()!"); - if (g.NavDisableMouseHover && !g.NavDisableHighlight && !(flags & ImGuiHoveredFlags_NoNavOverride)) { if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) return false; if (!IsItemFocused()) return false; - - if (flags & ImGuiHoveredFlags_ForTooltip) - flags |= g.Style.HoverFlagsForTooltipNav; } else { @@ -4013,10 +3644,6 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags; if (!(status_flags & ImGuiItemStatusFlags_HoveredRect)) return false; - - if (flags & ImGuiHoveredFlags_ForTooltip) - flags |= g.Style.HoverFlagsForTooltipMouse; - IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy)) == 0); // Flags not supported by this function // Done with rectangle culling so we can perform heavier checks now @@ -4026,13 +3653,12 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was // the test that has been running for a long while. if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0) - if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByWindow) == 0) + if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0) return false; // Test if another item is active (e.g. being dragged) - const ImGuiID id = g.LastItemData.ID; if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0) - if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) + if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) return false; // Test if interactions on this window are blocked by an active popup or modal. @@ -4045,61 +3671,49 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) return false; // Special handling for calling after Begin() which represent the title bar or tab. - // When the window is skipped/collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. - if (id == window->MoveId && window->WriteAccessed) + // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. + if (g.LastItemData.ID == window->MoveId && window->WriteAccessed) return false; - - // Test if using AllowOverlap and overlapped - if ((g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap) && id != 0) - if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByItem) == 0) - if (g.HoveredIdPreviousFrame != g.LastItemData.ID) - return false; } // Handle hover delay // (some ideas: https://www.nngroup.com/articles/timing-exposing-content) - const float delay = CalcDelayFromHoveredFlags(flags); - if (delay > 0.0f || (flags & ImGuiHoveredFlags_Stationary)) + float delay; + if (flags & ImGuiHoveredFlags_DelayNormal) + delay = g.IO.HoverDelayNormal; + else if (flags & ImGuiHoveredFlags_DelayShort) + delay = g.IO.HoverDelayShort; + else + delay = 0.0f; + if (delay > 0.0f) { ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromRectangle(g.LastItemData.Rect); - if ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverItemDelayIdPreviousFrame != hover_delay_id)) - g.HoverItemDelayTimer = 0.0f; - g.HoverItemDelayId = hover_delay_id; - - // When changing hovered item we requires a bit of stationary delay before activating hover timer, - // but once unlocked on a given item we also moving. - //if (g.HoverDelayTimer >= delay && (g.HoverDelayTimer - g.IO.DeltaTime < delay || g.MouseStationaryTimer - g.IO.DeltaTime < g.Style.HoverStationaryDelay)) { IMGUI_DEBUG_LOG("HoverDelayTimer = %f/%f, MouseStationaryTimer = %f\n", g.HoverDelayTimer, delay, g.MouseStationaryTimer); } - if ((flags & ImGuiHoveredFlags_Stationary) != 0 && g.HoverItemUnlockedStationaryId != hover_delay_id) - return false; - - if (g.HoverItemDelayTimer < delay) - return false; + if ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverDelayIdPreviousFrame != hover_delay_id)) + g.HoverDelayTimer = 0.0f; + g.HoverDelayId = hover_delay_id; + return g.HoverDelayTimer >= delay; } return true; } // Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). -// (this does not rely on LastItemData it can be called from a ButtonBehavior() call not following an ItemAdd() call) -// FIXME-LEGACY: the 'ImGuiItemFlags item_flags' parameter was added on 2023-06-28. -// If you used this in your legacy/custom widgets code: -// - Commonly: if your ItemHoverable() call comes after an ItemAdd() call: pass 'item_flags = g.LastItemData.InFlags'. -// - Rare: otherwise you may pass 'item_flags = 0' (ImGuiItemFlags_None) unless you want to benefit from special behavior handled by ItemHoverable. -bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags) +bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - if (g.HoveredWindow != window) - return false; - if (!IsMouseHoveringRect(bb.Min, bb.Max)) + if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) return false; - if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) + ImGuiWindow* window = g.CurrentWindow; + if (g.HoveredWindow != window) return false; if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) return false; + if (!IsMouseHoveringRect(bb.Min, bb.Max)) + return false; // Done with rectangle culling so we can perform heavier checks now. + ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) { g.HoveredIdDisabled = true; @@ -4109,28 +3723,13 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level // hover test in widgets code. We could also decide to split this function is two. if (id != 0) - { - // Drag source doesn't report as hovered - if (g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover)) - return false; - SetHoveredID(id); - // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. - // This allows using patterns where a later submitted widget overlaps a previous one. Generally perceived as a front-to-back hit-test. - if (item_flags & ImGuiItemflags_AllowOverlap) - { - g.HoveredIdAllowOverlap = true; - if (g.HoveredIdPreviousFrame != id) - return false; - } - } - // When disabled we'll return false but still set HoveredId if (item_flags & ImGuiItemFlags_Disabled) { // Release active id if turning disabled - if (g.ActiveId == id && id != 0) + if (g.ActiveId == id) ClearActiveID(); g.HoveredIdDisabled = true; return false; @@ -4167,14 +3766,14 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id) } // This is also inlined in ItemAdd() -// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set g.LastItemData.DisplayRect. +// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set window->DC.LastItemDisplayRect! void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect) { ImGuiContext& g = *GImGui; g.LastItemData.ID = item_id; g.LastItemData.InFlags = in_flags; g.LastItemData.StatusFlags = item_flags; - g.LastItemData.Rect = g.LastItemData.NavRect = item_rect; + g.LastItemData.Rect = item_rect; } float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) @@ -4236,6 +3835,89 @@ const char* ImGui::GetVersion() return IMGUI_VERSION; } +// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself +// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module +ImGuiContext* ImGui::GetCurrentContext() +{ + return GImGui; +} + +void ImGui::SetCurrentContext(ImGuiContext* ctx) +{ +#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC + IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this. +#else + GImGui = ctx; +#endif +} + +void ImGui::SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data) +{ + GImAllocatorAllocFunc = alloc_func; + GImAllocatorFreeFunc = free_func; + GImAllocatorUserData = user_data; +} + +// This is provided to facilitate copying allocators from one static/DLL boundary to another (e.g. retrieve default allocator of your executable address space) +void ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data) +{ + *p_alloc_func = GImAllocatorAllocFunc; + *p_free_func = GImAllocatorFreeFunc; + *p_user_data = GImAllocatorUserData; +} + +ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) +{ + ImGuiContext* prev_ctx = GetCurrentContext(); + ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); + SetCurrentContext(ctx); + Initialize(); + if (prev_ctx != NULL) + SetCurrentContext(prev_ctx); // Restore previous context if any, else keep new one. + return ctx; +} + +void ImGui::DestroyContext(ImGuiContext* ctx) +{ + ImGuiContext* prev_ctx = GetCurrentContext(); + if (ctx == NULL) //-V1051 + ctx = prev_ctx; + SetCurrentContext(ctx); + Shutdown(); + SetCurrentContext((prev_ctx != ctx) ? prev_ctx : NULL); + IM_DELETE(ctx); +} + +// No specific ordering/dependency support, will see as needed +ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook) +{ + ImGuiContext& g = *ctx; + IM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_); + g.Hooks.push_back(*hook); + g.Hooks.back().HookId = ++g.HookIdNext; + return g.HookIdNext; +} + +// Deferred removal, avoiding issue with changing vector while iterating it +void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id) +{ + ImGuiContext& g = *ctx; + IM_ASSERT(hook_id != 0); + for (int n = 0; n < g.Hooks.Size; n++) + if (g.Hooks[n].HookId == hook_id) + g.Hooks[n].Type = ImGuiContextHookType_PendingRemoval_; +} + +// Call context hooks (used by e.g. test engine) +// We assume a small number of hooks so all stored in same array +void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type) +{ + ImGuiContext& g = *ctx; + for (int n = 0; n < g.Hooks.Size; n++) + if (g.Hooks[n].Type == hook_type) + g.Hooks[n].Callback(&g, &g.Hooks[n]); +} + ImGuiIO& ImGui::GetIO() { IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); @@ -4404,10 +4086,10 @@ void ImGui::UpdateMouseMovingWindowEndFrame() if (g.HoveredIdDisabled) g.MovingWindow = NULL; } - else if (root_window == NULL && g.NavWindow != NULL) + else if (root_window == NULL && g.NavWindow != NULL && GetTopMostPopupModal() == NULL) { // Clicking on void disable focus - FocusWindow(NULL, ImGuiFocusRequestFlags_UnlessBelowModal); + FocusWindow(NULL); } } @@ -4429,95 +4111,430 @@ static bool IsWindowActiveAndVisible(ImGuiWindow* window) return (window->Active) && (!window->Hidden); } -// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app) -void ImGui::UpdateHoveredWindowAndCaptureFlags() +static void UpdateAliasKey(ImGuiKey key, bool v, float analog_value) { - ImGuiContext& g = *GImGui; - ImGuiIO& io = g.IO; - g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING)); - - // Find the window hovered by mouse: - // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. - // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame. - // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms. - bool clear_hovered_windows = false; - FindHoveredWindow(); - - // Modal windows prevents mouse from hovering behind them. - ImGuiWindow* modal_window = GetTopMostPopupModal(); - if (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window)) - clear_hovered_windows = true; - - // Disabled mouse? - if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) - clear_hovered_windows = true; + IM_ASSERT(ImGui::IsAliasKey(key)); + ImGuiKeyData* key_data = ImGui::GetKeyData(key); + key_data->Down = v; + key_data->AnalogValue = analog_value; +} - // We track click ownership. When clicked outside of a window the click is owned by the application and - // won't report hovering nor request capture even while dragging over our windows afterward. - const bool has_open_popup = (g.OpenPopupStack.Size > 0); - const bool has_open_modal = (modal_window != NULL); - int mouse_earliest_down = -1; - bool mouse_any_down = false; - for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) +// Rewrite routing data buffers to strip old entries + sort by key to make queries not touch scattered data. +// Entries D,A,B,B,A,C,B --> A,A,B,B,B,C,D +// Index A:1 B:2 C:5 D:0 --> A:0 B:2 C:5 D:6 +// See 'Metrics->Key Owners & Shortcut Routing' to visualize the result of that operation. +static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt) +{ + ImGuiContext& g = *GImGui; + rt->EntriesNext.resize(0); + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { - if (io.MouseClicked[i]) + const int new_routing_start_idx = rt->EntriesNext.Size; + ImGuiKeyRoutingData* routing_entry; + for (int old_routing_idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; old_routing_idx != -1; old_routing_idx = routing_entry->NextEntryIndex) { - io.MouseDownOwned[i] = (g.HoveredWindow != NULL) || has_open_popup; - io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal; + routing_entry = &rt->Entries[old_routing_idx]; + routing_entry->RoutingCurr = routing_entry->RoutingNext; // Update entry + routing_entry->RoutingNext = ImGuiKeyOwner_None; + routing_entry->RoutingNextScore = 255; + if (routing_entry->RoutingCurr == ImGuiKeyOwner_None) + continue; + rt->EntriesNext.push_back(*routing_entry); // Write alive ones into new buffer + + // Apply routing to owner if there's no owner already (RoutingCurr == None at this point) + if (routing_entry->Mods == g.IO.KeyMods) + { + ImGuiKeyOwnerData* owner_data = ImGui::GetKeyOwnerData(key); + if (owner_data->OwnerCurr == ImGuiKeyOwner_None) + owner_data->OwnerCurr = routing_entry->RoutingCurr; + } } - mouse_any_down |= io.MouseDown[i]; - if (io.MouseDown[i]) - if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down]) - mouse_earliest_down = i; + + // Rewrite linked-list + rt->Index[key - ImGuiKey_NamedKey_BEGIN] = (ImGuiKeyRoutingIndex)(new_routing_start_idx < rt->EntriesNext.Size ? new_routing_start_idx : -1); + for (int n = new_routing_start_idx; n < rt->EntriesNext.Size; n++) + rt->EntriesNext[n].NextEntryIndex = (ImGuiKeyRoutingIndex)((n + 1 < rt->EntriesNext.Size) ? n + 1 : -1); } - const bool mouse_avail = (mouse_earliest_down == -1) || io.MouseDownOwned[mouse_earliest_down]; - const bool mouse_avail_unless_popup_close = (mouse_earliest_down == -1) || io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down]; + rt->Entries.swap(rt->EntriesNext); // Swap new and old indexes +} - // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. - // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) - const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; - if (!mouse_avail && !mouse_dragging_extern_payload) - clear_hovered_windows = true; +// [Internal] Do not use directly (should read io.KeyMods instead) +static ImGuiKeyChord GetMergedModsFromBools() +{ + ImGuiContext& g = *GImGui; + ImGuiKeyChord key_chord = 0; + if (g.IO.KeyCtrl) { key_chord |= ImGuiMod_Ctrl; } + if (g.IO.KeyShift) { key_chord |= ImGuiMod_Shift; } + if (g.IO.KeyAlt) { key_chord |= ImGuiMod_Alt; } + if (g.IO.KeySuper) { key_chord |= ImGuiMod_Super; } + return key_chord; +} - if (clear_hovered_windows) - g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; +static void ImGui::UpdateKeyboardInputs() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; - // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to Dear ImGui only, false = dispatch mouse to Dear ImGui + underlying app) - // Update io.WantCaptureMouseAllowPopupClose (experimental) to give a chance for app to react to popup closure with a drag - if (g.WantCaptureMouseNextFrame != -1) + // Import legacy keys or verify they are not used +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + if (io.BackendUsingLegacyKeyArrays == 0) { - io.WantCaptureMouse = io.WantCaptureMouseUnlessPopupClose = (g.WantCaptureMouseNextFrame != 0); + // Backend used new io.AddKeyEvent() API: Good! Verify that old arrays are never written to externally. + for (int n = 0; n < ImGuiKey_LegacyNativeKey_END; n++) + IM_ASSERT((io.KeysDown[n] == false || IsKeyDown((ImGuiKey)n)) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); } else { - io.WantCaptureMouse = (mouse_avail && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_popup; - io.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_modal; - } - - // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app) - if (g.WantCaptureKeyboardNextFrame != -1) - io.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); - else - io.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); - if (io.NavActive && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) - io.WantCaptureKeyboard = true; - - // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible - io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; -} + if (g.FrameCount == 0) + for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) + IM_ASSERT(g.IO.KeyMap[n] == -1 && "Backend is not allowed to write to io.KeyMap[0..511]!"); -void ImGui::NewFrame() -{ - IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); - ImGuiContext& g = *GImGui; + // Build reverse KeyMap (Named -> Legacy) + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++) + if (io.KeyMap[n] != -1) + { + IM_ASSERT(IsLegacyKey((ImGuiKey)io.KeyMap[n])); + io.KeyMap[io.KeyMap[n]] = n; + } - // Remove pending delete hooks before frame start. - // This deferred removal avoid issues of removal while iterating the hook vector - for (int n = g.Hooks.Size - 1; n >= 0; n--) - if (g.Hooks[n].Type == ImGuiContextHookType_PendingRemoval_) - g.Hooks.erase(&g.Hooks[n]); + // Import legacy keys into new ones + for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) + if (io.KeysDown[n] || io.BackendUsingLegacyKeyArrays == 1) + { + const ImGuiKey key = (ImGuiKey)(io.KeyMap[n] != -1 ? io.KeyMap[n] : n); + IM_ASSERT(io.KeyMap[n] == -1 || IsNamedKey(key)); + io.KeysData[key].Down = io.KeysDown[n]; + if (key != n) + io.KeysDown[key] = io.KeysDown[n]; // Allow legacy code using io.KeysDown[GetKeyIndex()] with old backends + io.BackendUsingLegacyKeyArrays = 1; + } + if (io.BackendUsingLegacyKeyArrays == 1) + { + GetKeyData(ImGuiMod_Ctrl)->Down = io.KeyCtrl; + GetKeyData(ImGuiMod_Shift)->Down = io.KeyShift; + GetKeyData(ImGuiMod_Alt)->Down = io.KeyAlt; + GetKeyData(ImGuiMod_Super)->Down = io.KeySuper; + } + } - CallContextHooks(&g, ImGuiContextHookType_NewFramePre); +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + if (io.BackendUsingLegacyNavInputArray && nav_gamepad_active) + { + #define MAP_LEGACY_NAV_INPUT_TO_KEY1(_KEY, _NAV1) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f); io.KeysData[_KEY].AnalogValue = io.NavInputs[_NAV1]; } while (0) + #define MAP_LEGACY_NAV_INPUT_TO_KEY2(_KEY, _NAV1, _NAV2) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f) || (io.NavInputs[_NAV2] > 0.0f); io.KeysData[_KEY].AnalogValue = ImMax(io.NavInputs[_NAV1], io.NavInputs[_NAV2]); } while (0) + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceDown, ImGuiNavInput_Activate); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceRight, ImGuiNavInput_Cancel); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceLeft, ImGuiNavInput_Menu); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceUp, ImGuiNavInput_Input); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadLeft, ImGuiNavInput_DpadLeft); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadRight, ImGuiNavInput_DpadRight); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadUp, ImGuiNavInput_DpadUp); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadDown, ImGuiNavInput_DpadDown); + MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadL1, ImGuiNavInput_FocusPrev, ImGuiNavInput_TweakSlow); + MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadR1, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakFast); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickLeft, ImGuiNavInput_LStickLeft); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickRight, ImGuiNavInput_LStickRight); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickUp, ImGuiNavInput_LStickUp); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickDown, ImGuiNavInput_LStickDown); + #undef NAV_MAP_KEY + } +#endif + +#endif + + // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools, update aliases + io.KeyMods = GetMergedModsFromBools(); + for (int n = 0; n < ImGuiMouseButton_COUNT; n++) + UpdateAliasKey(MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] ? 1.0f : 0.0f); + UpdateAliasKey(ImGuiKey_MouseWheelX, io.MouseWheelH != 0.0f, io.MouseWheelH); + UpdateAliasKey(ImGuiKey_MouseWheelY, io.MouseWheel != 0.0f, io.MouseWheel); + + // Clear gamepad data if disabled + if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0) + for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++) + { + io.KeysData[i - ImGuiKey_KeysData_OFFSET].Down = false; + io.KeysData[i - ImGuiKey_KeysData_OFFSET].AnalogValue = 0.0f; + } + + // Update keys + for (int i = 0; i < ImGuiKey_KeysData_SIZE; i++) + { + ImGuiKeyData* key_data = &io.KeysData[i]; + key_data->DownDurationPrev = key_data->DownDuration; + key_data->DownDuration = key_data->Down ? (key_data->DownDuration < 0.0f ? 0.0f : key_data->DownDuration + io.DeltaTime) : -1.0f; + } + + // Update keys/input owner (named keys only): one entry per key + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + { + ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_KeysData_OFFSET]; + ImGuiKeyOwnerData* owner_data = &g.KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; + owner_data->OwnerCurr = owner_data->OwnerNext; + if (!key_data->Down) // Important: ownership is released on the frame after a release. Ensure a 'MouseDown -> CloseWindow -> MouseUp' chain doesn't lead to someone else seeing the MouseUp. + owner_data->OwnerNext = ImGuiKeyOwner_None; + owner_data->LockThisFrame = owner_data->LockUntilRelease = owner_data->LockUntilRelease && key_data->Down; // Clear LockUntilRelease when key is not Down anymore + } + + UpdateKeyRoutingTable(&g.KeysRoutingTable); +} + +static void ImGui::UpdateMouseInputs() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) + if (IsMousePosValid(&io.MousePos)) + io.MousePos = g.MouseLastValidPos = ImFloorSigned(io.MousePos); + + // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta + if (IsMousePosValid(&io.MousePos) && IsMousePosValid(&io.MousePosPrev)) + io.MouseDelta = io.MousePos - io.MousePosPrev; + else + io.MouseDelta = ImVec2(0.0f, 0.0f); + + // If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. + if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) + g.NavDisableMouseHover = false; + + io.MousePosPrev = io.MousePos; + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + { + io.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f; + io.MouseClickedCount[i] = 0; // Will be filled below + io.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0f; + io.MouseDownDurationPrev[i] = io.MouseDownDuration[i]; + io.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0.0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f; + if (io.MouseClicked[i]) + { + bool is_repeated_click = false; + if ((float)(g.Time - io.MouseClickedTime[i]) < io.MouseDoubleClickTime) + { + ImVec2 delta_from_click_pos = IsMousePosValid(&io.MousePos) ? (io.MousePos - io.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + if (ImLengthSqr(delta_from_click_pos) < io.MouseDoubleClickMaxDist * io.MouseDoubleClickMaxDist) + is_repeated_click = true; + } + if (is_repeated_click) + io.MouseClickedLastCount[i]++; + else + io.MouseClickedLastCount[i] = 1; + io.MouseClickedTime[i] = g.Time; + io.MouseClickedPos[i] = io.MousePos; + io.MouseClickedCount[i] = io.MouseClickedLastCount[i]; + io.MouseDragMaxDistanceSqr[i] = 0.0f; + } + else if (io.MouseDown[i]) + { + // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold + float delta_sqr_click_pos = IsMousePosValid(&io.MousePos) ? ImLengthSqr(io.MousePos - io.MouseClickedPos[i]) : 0.0f; + io.MouseDragMaxDistanceSqr[i] = ImMax(io.MouseDragMaxDistanceSqr[i], delta_sqr_click_pos); + } + + // We provide io.MouseDoubleClicked[] as a legacy service + io.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2); + + // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation + if (io.MouseClicked[i]) + g.NavDisableMouseHover = false; + } +} + +static void LockWheelingWindow(ImGuiWindow* window, float wheel_amount) +{ + ImGuiContext& g = *GImGui; + if (window) + g.WheelingWindowReleaseTimer = ImMin(g.WheelingWindowReleaseTimer + ImAbs(wheel_amount) * WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER, WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER); + else + g.WheelingWindowReleaseTimer = 0.0f; + if (g.WheelingWindow == window) + return; + IMGUI_DEBUG_LOG_IO("LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL"); + g.WheelingWindow = window; + g.WheelingWindowRefMousePos = g.IO.MousePos; +} + +void ImGui::UpdateMouseWheel() +{ + ImGuiContext& g = *GImGui; + + // Reset the locked window if we move the mouse or after the timer elapses + if (g.WheelingWindow != NULL) + { + g.WheelingWindowReleaseTimer -= g.IO.DeltaTime; + if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold) + g.WheelingWindowReleaseTimer = 0.0f; + if (g.WheelingWindowReleaseTimer <= 0.0f) + LockWheelingWindow(NULL, 0.0f); + } + + ImVec2 wheel; + wheel.x = TestKeyOwner(ImGuiKey_MouseWheelX, ImGuiKeyOwner_None) ? g.IO.MouseWheelH : 0.0f; + wheel.y = TestKeyOwner(ImGuiKey_MouseWheelY, ImGuiKeyOwner_None) ? g.IO.MouseWheel : 0.0f; + if (wheel.x == 0.0f && wheel.y == 0.0f) + return; + + //IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y); + ImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow; + if (!mouse_window || mouse_window->Collapsed) + return; + + // Zoom / Scale window + // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned. + if (wheel.y != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling) + { + LockWheelingWindow(mouse_window, wheel.y); + ImGuiWindow* window = mouse_window; + const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); + const float scale = new_font_scale / window->FontWindowScale; + window->FontWindowScale = new_font_scale; + if (window == window->RootWindow) + { + const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; + SetWindowPos(window, window->Pos + offset, 0); + window->Size = ImFloor(window->Size * scale); + window->SizeFull = ImFloor(window->SizeFull * scale); + } + return; + } + if (g.IO.KeyCtrl) + return; + + // Mouse wheel scrolling + // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead + // (we avoid doing it on OSX as it the OS input layer handles this already) + const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors; + if (swap_axis) + { + wheel.x = wheel.y; + wheel.y = 0.0f; + } + + // Vertical Mouse Wheel scrolling + // Bubble up into parent window if: + // - a child window doesn't allow any scrolling. + // - a child window doesn't need scrolling because it is already at the edge for the direction we are going in. + // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag. + if (wheel.y != 0.0f) + { + ImGuiWindow* window = mouse_window; + while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) + window = window->ParentWindow; + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) + { + LockWheelingWindow(mouse_window, wheel.y); + float max_step = window->InnerRect.GetHeight() * 0.67f; + float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step)); + SetScrollY(window, window->Scroll.y - wheel.y * scroll_step); + } + } + + // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held + if (wheel.x != 0.0f) + { + ImGuiWindow* window = mouse_window; + while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) + window = window->ParentWindow; + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) + { + LockWheelingWindow(mouse_window, wheel.x); + float max_step = window->InnerRect.GetWidth() * 0.67f; + float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step)); + SetScrollX(window, window->Scroll.x - wheel.x * scroll_step); + } + } +} + +// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app) +void ImGui::UpdateHoveredWindowAndCaptureFlags() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING)); + + // Find the window hovered by mouse: + // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. + // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame. + // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms. + bool clear_hovered_windows = false; + FindHoveredWindow(); + + // Modal windows prevents mouse from hovering behind them. + ImGuiWindow* modal_window = GetTopMostPopupModal(); + if (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window)) + clear_hovered_windows = true; + + // Disabled mouse? + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) + clear_hovered_windows = true; + + // We track click ownership. When clicked outside of a window the click is owned by the application and + // won't report hovering nor request capture even while dragging over our windows afterward. + const bool has_open_popup = (g.OpenPopupStack.Size > 0); + const bool has_open_modal = (modal_window != NULL); + int mouse_earliest_down = -1; + bool mouse_any_down = false; + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + { + if (io.MouseClicked[i]) + { + io.MouseDownOwned[i] = (g.HoveredWindow != NULL) || has_open_popup; + io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal; + } + mouse_any_down |= io.MouseDown[i]; + if (io.MouseDown[i]) + if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down]) + mouse_earliest_down = i; + } + const bool mouse_avail = (mouse_earliest_down == -1) || io.MouseDownOwned[mouse_earliest_down]; + const bool mouse_avail_unless_popup_close = (mouse_earliest_down == -1) || io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down]; + + // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. + // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) + const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; + if (!mouse_avail && !mouse_dragging_extern_payload) + clear_hovered_windows = true; + + if (clear_hovered_windows) + g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; + + // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to Dear ImGui only, false = dispatch mouse to Dear ImGui + underlying app) + // Update io.WantCaptureMouseAllowPopupClose (experimental) to give a chance for app to react to popup closure with a drag + if (g.WantCaptureMouseNextFrame != -1) + { + io.WantCaptureMouse = io.WantCaptureMouseUnlessPopupClose = (g.WantCaptureMouseNextFrame != 0); + } + else + { + io.WantCaptureMouse = (mouse_avail && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_popup; + io.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_modal; + } + + // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app) + if (g.WantCaptureKeyboardNextFrame != -1) + io.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); + else + io.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); + if (io.NavActive && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) + io.WantCaptureKeyboard = true; + + // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible + io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; +} + +void ImGui::NewFrame() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + ImGuiContext& g = *GImGui; + + // Remove pending delete hooks before frame start. + // This deferred removal avoid issues of removal while iterating the hook vector + for (int n = g.Hooks.Size - 1; n >= 0; n--) + if (g.Hooks[n].Type == ImGuiContextHookType_PendingRemoval_) + g.Hooks.erase(&g.Hooks[n]); + + CallContextHooks(&g, ImGuiContextHookType_NewFramePre); // Check and assert for various common IO and Configuration mistakes ErrorCheckNewFrameSanityChecks(); @@ -4539,11 +4556,6 @@ void ImGui::NewFrame() g.FramerateSecPerFrameCount = ImMin(g.FramerateSecPerFrameCount + 1, IM_ARRAYSIZE(g.FramerateSecPerFrame)); g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX; - // Process input queue (trickle as many events as possible), turn events into writes to IO structure - g.InputEventsTrail.resize(0); - UpdateInputEvents(g.IO.ConfigInputTrickleEventQueue); - - // Update viewports (after processing input queue, so io.MouseHoveredViewport is set) UpdateViewportsNewFrame(); // Setup current font and draw list shared data @@ -4636,33 +4648,21 @@ void ImGui::NewFrame() } #endif - // Record when we have been stationary as this state is preserved while over same item. - // FIXME: The way this is expressed means user cannot alter HoverStationaryDelay during the frame to use varying values. - // To allow this we should store HoverItemMaxStationaryTime+ID and perform the >= check in IsItemHovered() function. - if (g.HoverItemDelayId != 0 && g.MouseStationaryTimer >= g.Style.HoverStationaryDelay) - g.HoverItemUnlockedStationaryId = g.HoverItemDelayId; - else if (g.HoverItemDelayId == 0) - g.HoverItemUnlockedStationaryId = 0; - if (g.HoveredWindow != NULL && g.MouseStationaryTimer >= g.Style.HoverStationaryDelay) - g.HoverWindowUnlockedStationaryId = g.HoveredWindow->ID; - else if (g.HoveredWindow == NULL) - g.HoverWindowUnlockedStationaryId = 0; - // Update hover delay for IsItemHovered() with delays and tooltips - g.HoverItemDelayIdPreviousFrame = g.HoverItemDelayId; - if (g.HoverItemDelayId != 0) + g.HoverDelayIdPreviousFrame = g.HoverDelayId; + if (g.HoverDelayId != 0) { - g.HoverItemDelayTimer += g.IO.DeltaTime; - g.HoverItemDelayClearTimer = 0.0f; - g.HoverItemDelayId = 0; + //if (g.IO.MouseDelta.x == 0.0f && g.IO.MouseDelta.y == 0.0f) // Need design/flags + g.HoverDelayTimer += g.IO.DeltaTime; + g.HoverDelayClearTimer = 0.0f; + g.HoverDelayId = 0; } - else if (g.HoverItemDelayTimer > 0.0f) + else if (g.HoverDelayTimer > 0.0f) { // This gives a little bit of leeway before clearing the hover timer, allowing mouse to cross gaps - // We could expose 0.25f as style.HoverClearDelay but I am not sure of the logic yet, this is particularly subtle. - g.HoverItemDelayClearTimer += g.IO.DeltaTime; - if (g.HoverItemDelayClearTimer >= ImMax(0.25f, g.IO.DeltaTime * 2.0f)) // ~7 frames at 30 Hz + allow for low framerate - g.HoverItemDelayTimer = g.HoverItemDelayClearTimer = 0.0f; // May want a decaying timer, in which case need to clamp at max first, based on max of caller last requested timer. + g.HoverDelayClearTimer += g.IO.DeltaTime; + if (g.HoverDelayClearTimer >= ImMax(0.20f, g.IO.DeltaTime * 2.0f)) // ~6 frames at 30 Hz + allow for low framerate + g.HoverDelayTimer = g.HoverDelayClearTimer = 0.0f; // May want a decaying timer, in which case need to clamp at max first, based on max of caller last requested timer. } // Drag and drop @@ -4677,6 +4677,10 @@ void ImGui::NewFrame() //if (g.IO.AppFocusLost) // ClosePopupsExceptModals(); + // Process input queue (trickle as many events as possible) + g.InputEventsTrail.resize(0); + UpdateInputEvents(g.IO.ConfigInputTrickleEventQueue); + // Update keyboard input state UpdateKeyboardInputs(); @@ -4704,83 +4708,193 @@ void ImGui::NewFrame() else g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f); - g.MouseCursor = ImGuiMouseCursor_Arrow; - g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; + g.MouseCursor = ImGuiMouseCursor_Arrow; + g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; + + // Platform IME data: reset for the frame + g.PlatformImeDataPrev = g.PlatformImeData; + g.PlatformImeData.WantVisible = false; + + // Mouse wheel scrolling, scale + UpdateMouseWheel(); + + // Mark all windows as not visible and compact unused memory. + IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size); + const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer; + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + window->WasActive = window->Active; + window->Active = false; + window->WriteAccessed = false; + window->BeginCountPreviousFrame = window->BeginCount; + window->BeginCount = 0; + + // Garbage collect transient buffers of recently unused windows + if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) + GcCompactTransientWindowBuffers(window); + } + + // Garbage collect transient buffers of recently unused tables + for (int i = 0; i < g.TablesLastTimeActive.Size; i++) + if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time) + TableGcCompactTransientBuffers(g.Tables.GetByIndex(i)); + for (int i = 0; i < g.TablesTempData.Size; i++) + if (g.TablesTempData[i].LastTimeActive >= 0.0f && g.TablesTempData[i].LastTimeActive < memory_compact_start_time) + TableGcCompactTransientBuffers(&g.TablesTempData[i]); + if (g.GcCompactAll) + GcCompactTransientMiscBuffers(); + g.GcCompactAll = false; + + // Closing the focused window restore focus to the first active root window in descending z-order + if (g.NavWindow && !g.NavWindow->WasActive) + FocusTopMostWindowUnderOne(NULL, NULL); + + // No window should be open at the beginning of the frame. + // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. + g.CurrentWindowStack.resize(0); + g.BeginPopupStack.resize(0); + g.ItemFlagsStack.resize(0); + g.ItemFlagsStack.push_back(ImGuiItemFlags_None); + g.GroupStack.resize(0); + + // [DEBUG] Update debug features + UpdateDebugToolItemPicker(); + UpdateDebugToolStackQueries(); + if (g.DebugLocateFrames > 0 && --g.DebugLocateFrames == 0) + g.DebugLocateId = 0; + + // Create implicit/fallback window - which we will only render it if the user has added something to it. + // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. + // This fallback is particularly important as it prevents ImGui:: calls from crashing. + g.WithinFrameScopeWithImplicitWindow = true; + SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); + Begin("Debug##Default"); + IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true); + + CallContextHooks(&g, ImGuiContextHookType_NewFramePost); +} + +// IMPORTANT: ###xxx suffixes must be same in ALL languages +static const ImGuiLocEntry GLocalizationEntriesEnUS[] = +{ + { ImGuiLocKey_TableSizeOne, "Size column to fit###SizeOne" }, + { ImGuiLocKey_TableSizeAllFit, "Size all columns to fit###SizeAll" }, + { ImGuiLocKey_TableSizeAllDefault, "Size all columns to default###SizeAll" }, + { ImGuiLocKey_TableResetOrder, "Reset order###ResetOrder" }, + { ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" }, + { ImGuiLocKey_WindowingPopup, "(Popup)" }, + { ImGuiLocKey_WindowingUntitled, "(Untitled)" }, +}; + +void ImGui::Initialize() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(!g.Initialized && !g.SettingsLoaded); + + // Add .ini handle for ImGuiWindow and ImGuiTable types + { + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Window"; + ini_handler.TypeHash = ImHashStr("Window"); + ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll; + ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen; + ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine; + ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll; + ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll; + AddSettingsHandler(&ini_handler); + } + TableSettingsAddSettingsHandler(); + + // Setup default localization table + LocalizeRegisterEntries(GLocalizationEntriesEnUS, IM_ARRAYSIZE(GLocalizationEntriesEnUS)); + + // Create default viewport + ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(); + g.Viewports.push_back(viewport); + g.TempBuffer.resize(1024 * 3 + 1, 0); + +#ifdef IMGUI_HAS_DOCK +#endif + + g.Initialized = true; +} + +// This function is merely here to free heap allocations. +void ImGui::Shutdown() +{ + // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) + ImGuiContext& g = *GImGui; + if (g.IO.Fonts && g.FontAtlasOwnedByContext) + { + g.IO.Fonts->Locked = false; + IM_DELETE(g.IO.Fonts); + } + g.IO.Fonts = NULL; + g.DrawListSharedData.TempBuffer.clear(); + + // Cleanup of other data are conditional on actually having initialized Dear ImGui. + if (!g.Initialized) + return; + + // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file) + if (g.SettingsLoaded && g.IO.IniFilename != NULL) + SaveIniSettingsToDisk(g.IO.IniFilename); + + CallContextHooks(&g, ImGuiContextHookType_Shutdown); + + // Clear everything else + g.Windows.clear_delete(); + g.WindowsFocusOrder.clear(); + g.WindowsTempSortBuffer.clear(); + g.CurrentWindow = NULL; + g.CurrentWindowStack.clear(); + g.WindowsById.Clear(); + g.NavWindow = NULL; + g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; + g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; + g.MovingWindow = NULL; - // Platform IME data: reset for the frame - g.PlatformImeDataPrev = g.PlatformImeData; - g.PlatformImeData.WantVisible = false; + g.KeysRoutingTable.Clear(); - // Mouse wheel scrolling, scale - UpdateMouseWheel(); + g.ColorStack.clear(); + g.StyleVarStack.clear(); + g.FontStack.clear(); + g.OpenPopupStack.clear(); + g.BeginPopupStack.clear(); - // Mark all windows as not visible and compact unused memory. - IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size); - const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer; - for (int i = 0; i != g.Windows.Size; i++) - { - ImGuiWindow* window = g.Windows[i]; - window->WasActive = window->Active; - window->Active = false; - window->WriteAccessed = false; - window->BeginCountPreviousFrame = window->BeginCount; - window->BeginCount = 0; + g.Viewports.clear_delete(); - // Garbage collect transient buffers of recently unused windows - if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) - GcCompactTransientWindowBuffers(window); - } + g.TabBars.Clear(); + g.CurrentTabBarStack.clear(); + g.ShrinkWidthBuffer.clear(); - // Garbage collect transient buffers of recently unused tables - for (int i = 0; i < g.TablesLastTimeActive.Size; i++) - if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time) - TableGcCompactTransientBuffers(g.Tables.GetByIndex(i)); - for (int i = 0; i < g.TablesTempData.Size; i++) - if (g.TablesTempData[i].LastTimeActive >= 0.0f && g.TablesTempData[i].LastTimeActive < memory_compact_start_time) - TableGcCompactTransientBuffers(&g.TablesTempData[i]); - if (g.GcCompactAll) - GcCompactTransientMiscBuffers(); - g.GcCompactAll = false; + g.ClipperTempData.clear_destruct(); - // Closing the focused window restore focus to the first active root window in descending z-order - if (g.NavWindow && !g.NavWindow->WasActive) - FocusTopMostWindowUnderOne(NULL, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild); + g.Tables.Clear(); + g.TablesTempData.clear_destruct(); + g.DrawChannelsTempMergeBuffer.clear(); - // No window should be open at the beginning of the frame. - // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. - g.CurrentWindowStack.resize(0); - g.BeginPopupStack.resize(0); - g.ItemFlagsStack.resize(0); - g.ItemFlagsStack.push_back(ImGuiItemFlags_None); - g.GroupStack.resize(0); + g.ClipboardHandlerData.clear(); + g.MenusIdSubmittedThisFrame.clear(); + g.InputTextState.ClearFreeMemory(); - // [DEBUG] Update debug features - UpdateDebugToolItemPicker(); - UpdateDebugToolStackQueries(); - if (g.DebugLocateFrames > 0 && --g.DebugLocateFrames == 0) - g.DebugLocateId = 0; - if (g.DebugLogClipperAutoDisableFrames > 0 && --g.DebugLogClipperAutoDisableFrames == 0) + g.SettingsWindows.clear(); + g.SettingsHandlers.clear(); + + if (g.LogFile) { - DebugLog("(Auto-disabled ImGuiDebugLogFlags_EventClipper to avoid spamming)\n"); - g.DebugLogFlags &= ~ImGuiDebugLogFlags_EventClipper; +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + if (g.LogFile != stdout) +#endif + ImFileClose(g.LogFile); + g.LogFile = NULL; } + g.LogBuffer.clear(); + g.DebugLogBuf.clear(); + g.DebugLogIndex.clear(); - // Create implicit/fallback window - which we will only render it if the user has added something to it. - // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. - // This fallback is particularly important as it prevents ImGui:: calls from crashing. - g.WithinFrameScopeWithImplicitWindow = true; - SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); - Begin("Debug##Default"); - IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true); - - // [DEBUG] When io.ConfigDebugBeginReturnValue is set, we make Begin()/BeginChild() return false at different level of the window-stack, - // allowing to validate correct Begin/End behavior in user code. - if (g.IO.ConfigDebugBeginReturnValueLoop) - g.DebugBeginReturnValueCullDepth = (g.DebugBeginReturnValueCullDepth == -1) ? 0 : ((g.DebugBeginReturnValueCullDepth + ((g.FrameCount % 4) == 0 ? 1 : 0)) % 10); - else - g.DebugBeginReturnValueCullDepth = -1; - - CallContextHooks(&g, ImGuiContextHookType_NewFramePost); + g.Initialized = false; } // FIXME: Add a more explicit sort order in the window structure. @@ -4811,12 +4925,47 @@ static void AddWindowToSortBuffer(ImVector* out_sorted_windows, Im } } +static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list) +{ + if (draw_list->CmdBuffer.Size == 0) + return; + if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && draw_list->CmdBuffer[0].UserCallback == NULL) + return; + + // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. + // May trigger for you if you are using PrimXXX functions incorrectly. + IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); + IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); + if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset)) + IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); + + // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) + // If this assert triggers because you are drawing lots of stuff manually: + // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds. + // Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents. + // - If you want large meshes with more than 64K vertices, you can either: + // (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'. + // Most example backends already support this from 1.71. Pre-1.71 backends won't. + // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them. + // (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h. + // Most example backends already support this. For example, the OpenGL example code detect index size at compile-time: + // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); + // Your own engine or render API may use different parameters or function calls to specify index sizes. + // 2 and 4 bytes indices are generally supported by most graphics API. + // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching + // the 64K limit to split your draw commands in multiple draw lists. + if (sizeof(ImDrawIdx) == 2) + IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); + + out_list->push_back(draw_list); +} + static void AddWindowToDrawData(ImGuiWindow* window, int layer) { ImGuiContext& g = *GImGui; ImGuiViewportP* viewport = g.Viewports[0]; g.IO.MetricsRenderWindows++; - ImGui::AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[layer], window->DrawList); + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[layer], window->DrawList); for (int i = 0; i < window->DC.ChildWindows.Size; i++) { ImGuiWindow* child = window->DC.ChildWindows[i]; @@ -4836,41 +4985,42 @@ static inline void AddRootWindowToDrawData(ImGuiWindow* window) AddWindowToDrawData(window, GetWindowDisplayLayer(window)); } -static void FlattenDrawDataIntoSingleLayer(ImDrawDataBuilder* builder) +void ImDrawDataBuilder::FlattenIntoSingleLayer() { - int n = builder->Layers[0]->Size; - int full_size = n; - for (int i = 1; i < IM_ARRAYSIZE(builder->Layers); i++) - full_size += builder->Layers[i]->Size; - builder->Layers[0]->resize(full_size); - for (int layer_n = 1; layer_n < IM_ARRAYSIZE(builder->Layers); layer_n++) + int n = Layers[0].Size; + int size = n; + for (int i = 1; i < IM_ARRAYSIZE(Layers); i++) + size += Layers[i].Size; + Layers[0].resize(size); + for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++) { - ImVector* layer = builder->Layers[layer_n]; - if (layer->empty()) + ImVector& layer = Layers[layer_n]; + if (layer.empty()) continue; - memcpy(builder->Layers[0]->Data + n, layer->Data, layer->Size * sizeof(ImDrawList*)); - n += layer->Size; - layer->resize(0); + memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*)); + n += layer.Size; + layer.resize(0); } } -static void InitViewportDrawData(ImGuiViewportP* viewport) +static void SetupViewportDrawData(ImGuiViewportP* viewport, ImVector* draw_lists) { ImGuiIO& io = ImGui::GetIO(); ImDrawData* draw_data = &viewport->DrawDataP; - - viewport->DrawDataBuilder.Layers[0] = &draw_data->CmdLists; - viewport->DrawDataBuilder.Layers[1] = &viewport->DrawDataBuilder.LayerData1; - viewport->DrawDataBuilder.Layers[0]->resize(0); - viewport->DrawDataBuilder.Layers[1]->resize(0); - draw_data->Valid = true; - draw_data->CmdListsCount = 0; + draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL; + draw_data->CmdListsCount = draw_lists->Size; draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0; draw_data->DisplayPos = viewport->Pos; draw_data->DisplaySize = viewport->Size; draw_data->FramebufferScale = io.DisplayFramebufferScale; - draw_data->OwnerViewport = viewport; + for (int n = 0; n < draw_lists->Size; n++) + { + ImDrawList* draw_list = draw_lists->Data[n]; + draw_list->_PopUnusedDrawCmd(); + draw_data->TotalVtxCount += draw_list->VtxBuffer.Size; + draw_data->TotalIdxCount += draw_list->IdxBuffer.Size; + } } // Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering. @@ -4909,14 +5059,14 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 ImDrawList* draw_list = window->RootWindow->DrawList; if (draw_list->CmdBuffer.Size == 0) draw_list->AddDrawCmd(); - draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that) + draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // Ensure ImDrawCmd are not merged draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col); ImDrawCmd cmd = draw_list->CmdBuffer.back(); IM_ASSERT(cmd.ElemCount == 6); draw_list->CmdBuffer.pop_back(); draw_list->CmdBuffer.push_front(cmd); - draw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.back().IdxOffset won't be correct if we append to same command. draw_list->PopClipRect(); + draw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.back().IdxOffset won't be correct if we append to same command. } } @@ -4991,24 +5141,8 @@ void ImGui::EndFrame() ErrorCheckEndFrameSanityChecks(); // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) - ImGuiPlatformImeData* ime_data = &g.PlatformImeData; - if (g.IO.SetPlatformImeDataFn && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) - { - IMGUI_DEBUG_LOG_IO("[io] Calling io.SetPlatformImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y); - ImGuiViewport* viewport = GetMainViewport(); -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - if (viewport->PlatformHandleRaw == NULL && g.IO.ImeWindowHandle != NULL) - { - viewport->PlatformHandleRaw = g.IO.ImeWindowHandle; - g.IO.SetPlatformImeDataFn(viewport, ime_data); - viewport->PlatformHandleRaw = NULL; - } - else -#endif - { - g.IO.SetPlatformImeDataFn(viewport, ime_data); - } - } + if (g.IO.SetPlatformImeDataFn && memcmp(&g.PlatformImeData, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) + g.IO.SetPlatformImeDataFn(GetMainViewport(), &g.PlatformImeData); // Hide implicit/fallback "Debug" window if it hasn't been used g.WithinFrameScopeWithImplicitWindow = false; @@ -5091,9 +5225,9 @@ void ImGui::Render() for (int n = 0; n != g.Viewports.Size; n++) { ImGuiViewportP* viewport = g.Viewports[n]; - InitViewportDrawData(viewport); + viewport->DrawDataBuilder.Clear(); if (viewport->DrawLists[0] != NULL) - AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); } // Draw modal/window whitening backgrounds @@ -5124,18 +5258,14 @@ void ImGui::Render() for (int n = 0; n < g.Viewports.Size; n++) { ImGuiViewportP* viewport = g.Viewports[n]; - FlattenDrawDataIntoSingleLayer(&viewport->DrawDataBuilder); + viewport->DrawDataBuilder.FlattenIntoSingleLayer(); // Add foreground ImDrawList (for each active viewport) if (viewport->DrawLists[1] != NULL) - AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport)); + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport)); - // We call _PopUnusedDrawCmd() last thing, as RenderDimmedBackgrounds() rely on a valid command being there (especially in docking branch). + SetupViewportDrawData(viewport, &viewport->DrawDataBuilder.Layers[0]); ImDrawData* draw_data = &viewport->DrawDataP; - IM_ASSERT(draw_data->CmdLists.Size == draw_data->CmdListsCount); - for (int draw_list_n = 0; draw_list_n < draw_data->CmdLists.Size; draw_list_n++) - draw_data->CmdLists[draw_list_n]->_PopUnusedDrawCmd(); - g.IO.MetricsRenderVertices += draw_data->TotalVtxCount; g.IO.MetricsRenderIndices += draw_data->TotalIdxCount; } @@ -5316,28 +5446,17 @@ bool ImGui::IsItemEdited() return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Edited) != 0; } -// Allow next item to be overlapped by subsequent items. -// This works by requiring HoveredId to match for two subsequent frames, -// so if a following items overwrite it our interactions will naturally be disabled. -void ImGui::SetNextItemAllowOverlap() -{ - ImGuiContext& g = *GImGui; - g.NextItemData.ItemFlags |= ImGuiItemflags_AllowOverlap; -} - -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. -// FIXME-LEGACY: Use SetNextItemAllowOverlap() *before* your item instead. +// FIXME: Although this is exposed, its interaction and ideal idiom with using ImGuiButtonFlags_AllowItemOverlap flag are extremely confusing, need rework. void ImGui::SetItemAllowOverlap() { ImGuiContext& g = *GImGui; ImGuiID id = g.LastItemData.ID; if (g.HoveredId == id) g.HoveredIdAllowOverlap = true; - if (g.ActiveId == id) // Before we made this obsolete, most calls to SetItemAllowOverlap() used to avoid this path by testing g.ActiveId != id. + if (g.ActiveId == id) g.ActiveIdAllowOverlap = true; } -#endif // FIXME: It might be undesirable that this will likely disable KeyOwner-aware shortcuts systems. Consider a more fine-tuned version for the two users of this function. void ImGui::SetActiveIdUsingAllKeyboardKeys() @@ -5349,12 +5468,6 @@ void ImGui::SetActiveIdUsingAllKeyboardKeys() NavMoveRequestCancel(); } -ImGuiID ImGui::GetItemID() -{ - ImGuiContext& g = *GImGui; - return g.LastItemData.ID; -} - ImVec2 ImGui::GetItemRectMin() { ImGuiContext& g = *GImGui; @@ -5414,16 +5527,12 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b parent_window->DC.CursorPos = child_window->Pos; // Process navigation-in immediately so NavInit can run on first frame - // Can enter a child if (A) it has navigatable items or (B) it can be scrolled. - const ImGuiID temp_id_for_activation = ImHashStr("##Child", 0, id); - if (g.ActiveId == temp_id_for_activation) - ClearActiveID(); - if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY)) + if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavHasScroll)) { FocusWindow(child_window); NavInitWindow(child_window, false); - SetActiveID(temp_id_for_activation, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item - g.ActiveIdSource = g.NavInputSource; + SetActiveID(id + 1, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item + g.ActiveIdSource = ImGuiInputSource_Nav; } return ret; } @@ -5465,7 +5574,7 @@ void ImGui::EndChild() ImGuiWindow* parent_window = g.CurrentWindow; ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz); ItemSize(sz); - if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavWindowHasScrollY) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) + if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) { ItemAdd(bb, window->ChildId); RenderNavHighlight(bb, window->ChildId); @@ -5478,10 +5587,6 @@ void ImGui::EndChild() { // Not navigable into ItemAdd(bb, 0); - - // But when flattened we directly reach items, adjust active layer mask accordingly - if (window->Flags & ImGuiWindowFlags_NavFlattened) - parent_window->DC.NavLayersActiveMaskNext |= window->DC.NavLayersActiveMaskNext; } if (g.HoveredWindow == window) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; @@ -5560,22 +5665,32 @@ static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, window->IsExplicitChild = new_is_explicit_child; } -static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings) +static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) { - // Initial window state with e.g. default/arbitrary window position - // Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. + ImGuiContext& g = *GImGui; + //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags); + + // Create window the first time + ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); + window->Flags = flags; + g.WindowsById.SetVoidPtr(window->ID, window); + + // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); window->Pos = main_viewport->Pos + ImVec2(60, 60); - window->SetWindowPosAllowFlags = window->SetWindowSizeAllowFlags = window->SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; - if (settings != NULL) - { - SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); - ApplyWindowSettings(window, settings); - } + // User can disable loading and saving of settings. Tooltip and child windows also don't store settings. + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) + if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) + { + // Retrieve settings from .ini file + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); + ApplyWindowSettings(window, settings); + } window->DC.CursorStartPos = window->DC.CursorMaxPos = window->DC.IdealMaxPos = window->Pos; // So first call to CalcWindowContentSizes() doesn't return crazy values - if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) { window->AutoFitFramesX = window->AutoFitFramesY = 2; window->AutoFitOnlyGrows = false; @@ -5588,23 +5703,6 @@ static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* s window->AutoFitFramesY = 2; window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); } -} - -static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) -{ - // Create window the first time - //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags); - ImGuiContext& g = *GImGui; - ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); - window->Flags = flags; - g.WindowsById.SetVoidPtr(window->ID, window); - - ImGuiWindowSettings* settings = NULL; - if (!(flags & ImGuiWindowFlags_NoSavedSettings)) - if ((settings = ImGui::FindWindowSettingsByWindow(window)) != 0) - window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); - - InitOrLoadWindowSettings(window, settings); if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) g.Windows.push_front(window); // Quite slow but rare and only once @@ -5642,9 +5740,9 @@ static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& s if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) { ImGuiWindow* window_for_height = window; + const float decoration_up_height = window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight(); new_size = ImMax(new_size, g.Style.WindowMinSize); - const float minimum_height = window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f); - new_size.y = ImMax(new_size.y, minimum_height); // Reduce artifacts with very small windows + new_size.y = ImMax(new_size.y, decoration_up_height + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows } return new_size; } @@ -5673,10 +5771,9 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont { ImGuiContext& g = *GImGui; ImGuiStyle& style = g.Style; - const float decoration_w_without_scrollbars = window->DecoOuterSizeX1 + window->DecoOuterSizeX2 - window->ScrollbarSizes.x; - const float decoration_h_without_scrollbars = window->DecoOuterSizeY1 + window->DecoOuterSizeY2 - window->ScrollbarSizes.y; + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); ImVec2 size_pad = window->WindowPadding * 2.0f; - ImVec2 size_desired = size_contents + size_pad + ImVec2(decoration_w_without_scrollbars, decoration_h_without_scrollbars); + ImVec2 size_desired = size_contents + size_pad + ImVec2(0.0f, decoration_up_height); if (window->Flags & ImGuiWindowFlags_Tooltip) { // Tooltip always resize @@ -5697,8 +5794,8 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont // When the window cannot fit all contents (either because of constraints, either because screen is too small), // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit); - bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - decoration_w_without_scrollbars < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); - bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_h_without_scrollbars < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); + bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - 0.0f < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); + bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_up_height < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); if (will_have_scrollbar_x) size_auto_fit.y += style.ScrollbarSize; if (will_have_scrollbar_y) @@ -5822,11 +5919,6 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f); const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f; - ImRect clamp_rect = visibility_rect; - const bool window_move_from_title_bar = g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar); - if (window_move_from_title_bar) - clamp_rect.Min.y -= window->TitleBarHeight(); - ImVec2 pos_target(FLT_MAX, FLT_MAX); ImVec2 size_target(FLT_MAX, FLT_MAX); @@ -5863,8 +5955,8 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s { // Resize from any of the four corners // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position - ImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? clamp_rect.Min.x : -FLT_MAX, (def.CornerPosN.y == 1.0f || (def.CornerPosN.y == 0.0f && window_move_from_title_bar)) ? clamp_rect.Min.y : -FLT_MAX); - ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? clamp_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? clamp_rect.Max.y : +FLT_MAX); + ImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, def.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX); ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip corner_target = ImClamp(corner_target, clamp_min, clamp_max); CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target); @@ -5893,8 +5985,8 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s } if (held) { - ImVec2 clamp_min(border_n == ImGuiDir_Right ? clamp_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down || (border_n == ImGuiDir_Up && window_move_from_title_bar) ? clamp_rect.Min.y : -FLT_MAX); - ImVec2 clamp_max(border_n == ImGuiDir_Left ? clamp_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? clamp_rect.Max.y : +FLT_MAX); + ImVec2 clamp_min(border_n == ImGuiDir_Right ? visibility_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down ? visibility_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max(border_n == ImGuiDir_Left ? visibility_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? visibility_rect.Max.y : +FLT_MAX); ImVec2 border_target = window->Pos; border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING; border_target = ImClamp(border_target, clamp_min, clamp_max); @@ -5913,15 +6005,15 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s { ImVec2 nav_resize_dir; if (g.NavInputSource == ImGuiInputSource_Keyboard && g.IO.KeyShift) - nav_resize_dir = GetKeyMagnitude2d(ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow); + nav_resize_dir = GetKeyVector2d(ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow); if (g.NavInputSource == ImGuiInputSource_Gamepad) - nav_resize_dir = GetKeyMagnitude2d(ImGuiKey_GamepadDpadLeft, ImGuiKey_GamepadDpadRight, ImGuiKey_GamepadDpadUp, ImGuiKey_GamepadDpadDown); + nav_resize_dir = GetKeyVector2d(ImGuiKey_GamepadDpadLeft, ImGuiKey_GamepadDpadRight, ImGuiKey_GamepadDpadUp, ImGuiKey_GamepadDpadDown); if (nav_resize_dir.x != 0.0f || nav_resize_dir.y != 0.0f) { const float NAV_RESIZE_SPEED = 600.0f; const float resize_step = NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y); g.NavWindowingAccumDeltaSize += nav_resize_dir * resize_step; - g.NavWindowingAccumDeltaSize = ImMax(g.NavWindowingAccumDeltaSize, clamp_rect.Min - window->Pos - window->Size); // We need Pos+Size >= clmap_rect.Min, so Size >= clmap_rect.Min - Pos, so size_delta >= clmap_rect.Min - window->Pos - window->Size + g.NavWindowingAccumDeltaSize = ImMax(g.NavWindowingAccumDeltaSize, visibility_rect.Min - window->Pos - window->Size); // We need Pos+Size >= visibility_rect.Min, so Size >= visibility_rect.Min - Pos, so size_delta >= visibility_rect.Min - window->Pos - window->Size g.NavWindowingToggleLayer = false; g.NavDisableMouseHover = true; resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); @@ -5986,7 +6078,7 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) // Draw background and borders // Draw and handle scrollbars -void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size) +void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size) { ImGuiContext& g = *GImGui; ImGuiStyle& style = g.Style; @@ -6003,7 +6095,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar if (window->Collapsed) { // Title bar only - const float backup_border_size = style.FrameBorderSize; + float backup_border_size = style.FrameBorderSize; g.Style.FrameBorderSize = window->WindowBorderSize; ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); @@ -6051,25 +6143,21 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar Scrollbar(ImGuiAxis_Y); // Render resize grips (after their input handling so we don't have a frame of latency) - if (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize)) + if (!(flags & ImGuiWindowFlags_NoResize)) { for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) { - const ImU32 col = resize_grip_col[resize_grip_n]; - if ((col & IM_COL32_A_MASK) == 0) - continue; const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size))); window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size))); window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); - window->DrawList->PathFillConvex(col); + window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]); } } // Borders - if (handle_borders_and_resize_grips) - RenderWindowOuterBorders(window); + RenderWindowOuterBorders(window); } } @@ -6182,35 +6270,31 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags // When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) // should be positioned behind that modal window, unless the window was created inside the modal begin-stack. // In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. -// - WindowA // FindBlockingModal() returns Modal1 -// - WindowB // .. returns Modal1 +// - Window // FindBlockingModal() returns Modal1 +// - Window // .. returns Modal1 // - Modal1 // .. returns Modal2 -// - WindowC // .. returns Modal2 -// - WindowD // .. returns Modal2 +// - Window // .. returns Modal2 +// - Window // .. returns Modal2 // - Modal2 // .. returns Modal2 -// - WindowE // .. returns NULL -// Notes: -// - FindBlockingModal(NULL) == NULL is generally equivalent to GetTopMostPopupModal() == NULL. -// Only difference is here we check for ->Active/WasActive but it may be unecessary. -ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) +static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) { ImGuiContext& g = *GImGui; if (g.OpenPopupStack.Size <= 0) return NULL; // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal. - for (int i = 0; i < g.OpenPopupStack.Size; i++) + for (int i = g.OpenPopupStack.Size - 1; i >= 0; i--) { ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window; if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal)) continue; if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows. continue; - if (window == NULL) // FindBlockingModal(NULL) test for if FocusWindow(NULL) is naturally possible via a mouse click. - return popup_window; - if (IsWindowWithinBeginStackOf(window, popup_window)) // Window may be over modal - continue; - return popup_window; // Place window right below first block modal + if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed. + break; + for (ImGuiWindow* parent = popup_window->ParentWindowInBeginStack->RootWindow; parent != NULL; parent = parent->ParentWindowInBeginStack->RootWindow) + if (IsWindowWithinBeginStackOf(window, parent)) + return popup_window; // Place window above its begin stack parent. } return NULL; } @@ -6289,7 +6373,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) ImGuiWindowStackData window_stack_data; window_stack_data.Window = window; window_stack_data.ParentLastItemDataBackup = g.LastItemData; - window_stack_data.StackSizesOnBegin.SetToContextState(&g); + window_stack_data.StackSizesOnBegin.SetToCurrentState(); g.CurrentWindowStack.push_back(window_stack_data); if (flags & ImGuiWindowFlags_ChildMenu) g.BeginMenuCount++; @@ -6473,15 +6557,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // SIZE - // Outer Decoration Sizes - // (we need to clear ScrollbarSize immediatly as CalcWindowAutoFitSize() needs it and can be called from other locations). - const ImVec2 scrollbar_sizes_from_last_frame = window->ScrollbarSizes; - window->DecoOuterSizeX1 = 0.0f; - window->DecoOuterSizeX2 = 0.0f; - window->DecoOuterSizeY1 = window->TitleBarHeight() + window->MenuBarHeight(); - window->DecoOuterSizeY2 = 0.0f; - window->ScrollbarSizes = ImVec2(0.0f, 0.0f); - // Calculate auto-fit size, handle automatic resize const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal); if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) @@ -6520,6 +6595,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull); window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull; + // Decoration size + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); + // POSITION // Popup latch its initial position, will position itself when it appears next frame @@ -6580,15 +6658,31 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) want_focus = true; else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0) want_focus = true; + + ImGuiWindow* modal = GetTopMostPopupModal(); + if (modal != NULL && !IsWindowWithinBeginStackOf(window, modal)) + { + // Avoid focusing a window that is created outside of active modal. This will prevent active modal from being closed. + // Since window is not focused it would reappear at the same display position like the last time it was visible. + // In case of completely new windows it would go to the top (over current modal), but input to such window would still be blocked by modal. + // Position window behind a modal that is not a begin-parent of this window. + want_focus = false; + if (window == window->RootWindow) + { + ImGuiWindow* blocking_modal = FindBlockingModal(window); + IM_ASSERT(blocking_modal != NULL); + BringWindowToDisplayBehind(window, blocking_modal); + } + } } - // [Test Engine] Register whole window in the item system (before submitting further decorations) + // [Test Engine] Register whole window in the item system #ifdef IMGUI_ENABLE_TEST_ENGINE if (g.TestEngineHookItems) { IM_ASSERT(window->IDStack.Size == 1); window->IDStack.Size = 0; // As window->IDStack[0] == window->ID here, make sure TestEngine doesn't erroneously see window as parent of itself. - IMGUI_TEST_ENGINE_ITEM_ADD(window->ID, window->Rect(), NULL); + IMGUI_TEST_ENGINE_ITEM_ADD(window->Rect(), window->ID); IMGUI_TEST_ENGINE_ITEM_INFO(window->ID, window->Name, (g.HoveredWindow == window) ? ImGuiItemStatusFlags_HoveredRect : 0); window->IDStack.Size = 1; } @@ -6610,10 +6704,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (!window->Collapsed) { // When reading the current size we need to read it after size constraints have been applied. - // Intentionally use previous frame values for InnerRect and ScrollbarSizes. - // And when we use window->DecorationUp here it doesn't have ScrollbarSizes.y applied yet. - ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2)); - ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + scrollbar_sizes_from_last_frame; + // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. + ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height); + ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes; ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f; float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; @@ -6623,10 +6716,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (window->ScrollbarX && !window->ScrollbarY) window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); - - // Amend the partially filled window->DecorationXXX values. - window->DecoOuterSizeX2 += window->ScrollbarSizes.x; - window->DecoOuterSizeY2 += window->ScrollbarSizes.y; } // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING) @@ -6650,10 +6739,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - ScrollToRectEx() // - NavUpdatePageUpPageDown() // - Scrollbar() - window->InnerRect.Min.x = window->Pos.x + window->DecoOuterSizeX1; - window->InnerRect.Min.y = window->Pos.y + window->DecoOuterSizeY1; - window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->DecoOuterSizeX2; - window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->DecoOuterSizeY2; + window->InnerRect.Min.x = window->Pos.x; + window->InnerRect.Min.y = window->Pos.y + decoration_up_height; + window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x; + window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y; // Inner clipping rectangle. // Will extend a little bit outside the normal work region. @@ -6686,7 +6775,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Apply scrolling window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window); window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); - window->DecoInnerSizeX1 = window->DecoInnerSizeY1 = 0.0f; // DRAWING @@ -6706,8 +6794,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping childs ImGuiWindow* previous_child = parent_window->DC.ChildWindows.Size >= 2 ? parent_window->DC.ChildWindows[parent_window->DC.ChildWindows.Size - 2] : NULL; bool previous_child_overlapping = previous_child ? previous_child->Rect().Overlaps(window->Rect()) : false; - bool parent_is_empty = (parent_window->DrawList->VtxBuffer.Size == 0); - if (window->DrawList->CmdBuffer.back().ElemCount == 0 && !parent_is_empty && !previous_child_overlapping) + bool parent_is_empty = parent_window->DrawList->VtxBuffer.Size > 0; + if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_is_empty && !previous_child_overlapping) render_decorations_in_parent = true; } if (render_decorations_in_parent) @@ -6716,8 +6804,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Handle title bar, scrollbar, resize grips and resize borders const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); - const bool handle_borders_and_resize_grips = true; // This exists to facilitate merge with 'docking' branch. - RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_count, resize_grip_col, resize_grip_draw_size); + RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size); if (render_decorations_in_parent) window->DrawList = &window->DrawListInst; @@ -6732,8 +6819,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - BeginTabBar() for right-most edge const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar); - const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2))); - const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2))); + const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); + const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize)); window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize)); window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x; @@ -6742,24 +6829,23 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // [LEGACY] Content Region // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. - // Unless explicit content size is specified by user, this currently represent the region leading to no scrolling. // Used by: // - Mouse wheel scrolling + many other things - window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x + window->DecoOuterSizeX1; - window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->DecoOuterSizeY1; - window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2))); - window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2))); + window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; + window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height; + window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); + window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); // Setup drawing context // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) - window->DC.Indent.x = window->DecoOuterSizeX1 + window->WindowPadding.x - window->Scroll.x; + window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; window->DC.GroupOffset.x = 0.0f; window->DC.ColumnsOffset.x = 0.0f; // Record the loss of precision of CursorStartPos which can happen due to really large scrolling amount. // This is used by clipper to compensate and fix the most common use case of large scroll area. Easy and cheap, next best thing compared to switching everything to double or ImU64. - double start_pos_highp_x = (double)window->Pos.x + window->WindowPadding.x - (double)window->Scroll.x + window->DecoOuterSizeX1 + window->DC.ColumnsOffset.x; - double start_pos_highp_y = (double)window->Pos.y + window->WindowPadding.y - (double)window->Scroll.y + window->DecoOuterSizeY1; + double start_pos_highp_x = (double)window->Pos.x + window->WindowPadding.x - (double)window->Scroll.x + window->DC.ColumnsOffset.x; + double start_pos_highp_y = (double)window->Pos.y + window->WindowPadding.y - (double)window->Scroll.y + decoration_up_height; window->DC.CursorStartPos = ImVec2((float)start_pos_highp_x, (float)start_pos_highp_y); window->DC.CursorStartPosLossyness = ImVec2((float)(start_pos_highp_x - window->DC.CursorStartPos.x), (float)(start_pos_highp_y - window->DC.CursorStartPos.y)); window->DC.CursorPos = window->DC.CursorStartPos; @@ -6773,9 +6859,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.NavLayerCurrent = ImGuiNavLayer_Main; window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext; window->DC.NavLayersActiveMaskNext = 0x00; - window->DC.NavIsScrollPushableX = true; window->DC.NavHideHighlightOneFrame = false; - window->DC.NavWindowHasScrollY = (window->ScrollMax.y > 0.0f); + window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f); window->DC.MenuBarAppending = false; window->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user); @@ -6798,13 +6883,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->AutoFitFramesY--; // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there) - // We ImGuiFocusRequestFlags_UnlessBelowModal to: - // - Avoid focusing a window that is created outside of a modal. This will prevent active modal from being closed. - // - Position window behind the modal that is not a begin-parent of this window. if (want_focus) - FocusWindow(window, ImGuiFocusRequestFlags_UnlessBelowModal); - if (want_focus && window == g.NavWindow) + { + FocusWindow(window); NavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls + } // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) @@ -6833,10 +6916,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) DebugLocateItemResolveWithLastItem(); #endif - // [Test Engine] Register title bar / tab with MoveId. + // [Test Engine] Register title bar / tab #ifdef IMGUI_ENABLE_TEST_ENGINE if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) - IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.ID, g.LastItemData.Rect, &g.LastItemData); + IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.Rect, g.LastItemData.ID); #endif } else @@ -6898,15 +6981,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->SkipItems = skip_items; } - // [DEBUG] io.ConfigDebugBeginReturnValue override return value to test Begin/End and BeginChild/EndChild behaviors. - // (The implicit fallback window is NOT automatically ended allowing it to always be able to receive commands without crashing) - if (!window->IsFallbackWindow && ((g.IO.ConfigDebugBeginReturnValueOnce && window_just_created) || (g.IO.ConfigDebugBeginReturnValueLoop && g.DebugBeginReturnValueCullDepth == g.CurrentWindowStack.Size))) - { - if (window->AutoFitFramesX > 0) { window->AutoFitFramesX++; } - if (window->AutoFitFramesY > 0) { window->AutoFitFramesY++; } - return false; - } - return !window->SkipItems; } @@ -6946,7 +7020,7 @@ void ImGui::End() g.BeginMenuCount--; if (window->Flags & ImGuiWindowFlags_Popup) g.BeginPopupStack.pop_back(); - g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithContextState(&g); + g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithCurrentState(); g.CurrentWindowStack.pop_back(); SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window); } @@ -7030,25 +7104,10 @@ int ImGui::FindWindowDisplayIndex(ImGuiWindow* window) } // Moving window to front of display and set focus (which happens to be back of our sorted list) -void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) +void ImGui::FocusWindow(ImGuiWindow* window) { ImGuiContext& g = *GImGui; - // Modal check? - if ((flags & ImGuiFocusRequestFlags_UnlessBelowModal) && (g.NavWindow != window)) // Early out in common case. - if (ImGuiWindow* blocking_modal = FindBlockingModal(window)) - { - IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "", blocking_modal->Name); - if (window && window == window->RootWindow && (window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) - BringWindowToDisplayBehind(window, blocking_modal); // Still bring to right below modal. - return; - } - - // Find last focused child (if any) and focus it instead. - if ((flags & ImGuiFocusRequestFlags_RestoreFocusedChild) && window != NULL) - window = NavRestoreLastChildNavWindow(window); - - // Apply focus if (g.NavWindow != window) { SetNavWindow(window); @@ -7085,10 +7144,9 @@ void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) BringWindowToDisplayFront(display_front_window); } -void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags) +void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window) { ImGuiContext& g = *GImGui; - IM_UNUSED(filter_viewport); // Unused in master branch. int start_idx = g.WindowsFocusOrder.Size - 1; if (under_this_window != NULL) { @@ -7106,15 +7164,15 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. ImGuiWindow* window = g.WindowsFocusOrder[i]; IM_ASSERT(window == window->RootWindow); - if (window == ignore_window || !window->WasActive) - continue; - if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) - { - FocusWindow(window, flags); - return; - } + if (window != ignore_window && window->WasActive) + if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) + { + ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); + FocusWindow(focus_window); + return; + } } - FocusWindow(NULL, flags); + FocusWindow(NULL); } // Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. @@ -7207,12 +7265,13 @@ void ImGui::EndDisabled() g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar(); } -void ImGui::PushTabStop(bool tab_stop) +// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system. +void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) { - PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); + PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus); } -void ImGui::PopTabStop() +void ImGui::PopAllowKeyboardFocus() { PopItemFlag(); } @@ -7305,8 +7364,7 @@ bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_b bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) { - IM_ASSERT((flags & ~ImGuiHoveredFlags_AllowedMaskForIsWindowHovered) == 0 && "Invalid flags for IsWindowHovered()!"); - + IM_ASSERT((flags & (ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenDisabled)) == 0); // Flags not supported by this function ImGuiContext& g = *GImGui; ImGuiWindow* ref_window = g.HoveredWindow; ImGuiWindow* cur_window = g.CurrentWindow; @@ -7334,17 +7392,6 @@ bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != ref_window->MoveId) return false; - - // When changing hovered window we requires a bit of stationary delay before activating hover timer. - // FIXME: We don't support delay other than stationary one for now, other delay would need a way - // to fullfill the possibility that multiple IsWindowHovered() with varying flag could return true - // for different windows of the hierarchy. Possibly need a Hash(Current+Flags) ==> (Timer) cache. - // We can implement this for _Stationary because the data is linked to HoveredWindow rather than CurrentWindow. - if (flags & ImGuiHoveredFlags_ForTooltip) - flags |= g.Style.HoverFlagsForTooltipMouse; - if ((flags & ImGuiHoveredFlags_Stationary) != 0 && g.HoverWindowUnlockedStationaryId != ref_window->ID) - return false; - return true; } @@ -7492,12 +7539,6 @@ void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const I window->HitTestHoleOffset = ImVec2ih(pos - window->Pos); } -void ImGui::SetWindowHiddendAndSkipItemsForCurrentFrame(ImGuiWindow* window) -{ - window->Hidden = window->SkipItems = true; - window->HiddenFramesCanSkipItems = 1; -} - void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond) { SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond); @@ -7635,6 +7676,13 @@ void ImGui::SetWindowFontScale(float scale) g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); } +void ImGui::ActivateItem(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.NavNextActivateId = id; + g.NavNextActivateFlags = ImGuiActivateFlags_None; +} + void ImGui::PushFocusScope(ImGuiID id) { ImGuiContext& g = *GImGui; @@ -7650,40 +7698,13 @@ void ImGui::PopFocusScope() g.CurrentFocusScopeId = g.FocusScopeStack.Size ? g.FocusScopeStack.back() : 0; } -// Focus = move navigation cursor, set scrolling, set focus window. -void ImGui::FocusItem() -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - IMGUI_DEBUG_LOG_FOCUS("FocusItem(0x%08x) in window \"%s\"\n", g.LastItemData.ID, window->Name); - if (g.DragDropActive || g.MovingWindow != NULL) // FIXME: Opt-in flags for this? - { - IMGUI_DEBUG_LOG_FOCUS("FocusItem() ignored while DragDropActive!\n"); - return; - } - - ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_FocusApi | ImGuiNavMoveFlags_NoSelect; - ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; - SetNavWindow(window); - NavMoveRequestSubmit(ImGuiDir_None, ImGuiDir_Up, move_flags, scroll_flags); - NavMoveRequestResolveWithLastItem(&g.NavMoveResultLocal); -} - -void ImGui::ActivateItemByID(ImGuiID id) -{ - ImGuiContext& g = *GImGui; - g.NavNextActivateId = id; - g.NavNextActivateFlags = ImGuiActivateFlags_None; -} - // Note: this will likely be called ActivateItem() once we rework our Focus/Activation system! -// But ActivateItem() should function without altering scroll/focus? void ImGui::SetKeyboardFocusHere(int offset) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; IM_ASSERT(offset >= -1); // -1 is allowed but not below - IMGUI_DEBUG_LOG_FOCUS("SetKeyboardFocusHere(%d) in window \"%s\"\n", offset, window->Name); + IMGUI_DEBUG_LOG_ACTIVEID("SetKeyboardFocusHere(%d) in window \"%s\"\n", offset, window->Name); // It makes sense in the vast majority of cases to never interrupt a drag and drop. // When we refactor this function into ActivateItem() we may want to make this an option. @@ -7691,15 +7712,14 @@ void ImGui::SetKeyboardFocusHere(int offset) // is also automatically dropped in the event g.ActiveId is stolen. if (g.DragDropActive || g.MovingWindow != NULL) { - IMGUI_DEBUG_LOG_FOCUS("SetKeyboardFocusHere() ignored while DragDropActive!\n"); + IMGUI_DEBUG_LOG_ACTIVEID("SetKeyboardFocusHere() ignored while DragDropActive!\n"); return; } SetNavWindow(window); - ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate | ImGuiNavMoveFlags_FocusApi; ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; - NavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, move_flags, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. + NavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, ImGuiNavMoveFlags_Tabbing | ImGuiNavMoveFlags_FocusApi, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. if (offset == -1) { NavMoveRequestResolveWithLastItem(&g.NavMoveResultLocal); @@ -7717,15 +7737,16 @@ void ImGui::SetItemDefaultFocus() ImGuiWindow* window = g.CurrentWindow; if (!window->Appearing) return; - if (g.NavWindow != window->RootWindowForNav || (!g.NavInitRequest && g.NavInitResult.ID == 0) || g.NavLayer != window->DC.NavLayerCurrent) + if (g.NavWindow != window->RootWindowForNav || (!g.NavInitRequest && g.NavInitResultId == 0) || g.NavLayer != window->DC.NavLayerCurrent) return; g.NavInitRequest = false; - NavApplyItemToResult(&g.NavInitResult); + g.NavInitResultId = g.LastItemData.ID; + g.NavInitResultRectRel = WindowRectAbsToRel(window, g.LastItemData.Rect); NavUpdateAnyRequestFlag(); // Scroll could be done in NavInitRequestApplyResult() via an opt-in flag (we however don't want regular init requests to scroll) - if (!window->ClipRect.Contains(g.LastItemData.Rect)) + if (!IsItemVisible()) ScrollToRectEx(window, g.LastItemData.Rect, ImGuiScrollFlags_None); } @@ -7795,15 +7816,6 @@ ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed) return id; } -ImGuiID ImGui::GetIDWithSeed(int n, ImGuiID seed) -{ - ImGuiID id = ImHashData(&n, sizeof(n), seed); - ImGuiContext& g = *GImGui; - if (g.DebugHookIdInfo == id) - DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL); - return id; -} - void ImGui::PopID() { ImGuiWindow* window = GImGui->CurrentWindow; @@ -7845,82 +7857,46 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) //----------------------------------------------------------------------------- // [SECTION] INPUTS //----------------------------------------------------------------------------- -// - GetKeyData() [Internal] -// - GetKeyIndex() [Internal] -// - GetKeyName() -// - GetKeyChordName() [Internal] -// - CalcTypematicRepeatAmount() [Internal] -// - GetTypematicRepeatRate() [Internal] -// - GetKeyPressedAmount() [Internal] -// - GetKeyMagnitude2d() [Internal] -//----------------------------------------------------------------------------- -// - UpdateKeyRoutingTable() [Internal] -// - GetRoutingIdFromOwnerId() [Internal] -// - GetShortcutRoutingData() [Internal] -// - CalcRoutingScore() [Internal] -// - SetShortcutRouting() [Internal] -// - TestShortcutRouting() [Internal] -//----------------------------------------------------------------------------- -// - IsKeyDown() -// - IsKeyPressed() -// - IsKeyReleased() -//----------------------------------------------------------------------------- -// - IsMouseDown() -// - IsMouseClicked() -// - IsMouseReleased() -// - IsMouseDoubleClicked() -// - GetMouseClickedCount() -// - IsMouseHoveringRect() [Internal] -// - IsMouseDragPastThreshold() [Internal] -// - IsMouseDragging() -// - GetMousePos() -// - GetMousePosOnOpeningCurrentPopup() -// - IsMousePosValid() -// - IsAnyMouseDown() -// - GetMouseDragDelta() -// - ResetMouseDragDelta() -// - GetMouseCursor() -// - SetMouseCursor() -//----------------------------------------------------------------------------- -// - UpdateAliasKey() -// - GetMergedModsFromKeys() -// - UpdateKeyboardInputs() -// - UpdateMouseInputs() -//----------------------------------------------------------------------------- -// - LockWheelingWindow [Internal] -// - FindBestWheelingWindow [Internal] -// - UpdateMouseWheel() [Internal] -//----------------------------------------------------------------------------- -// - SetNextFrameWantCaptureKeyboard() -// - SetNextFrameWantCaptureMouse() -//----------------------------------------------------------------------------- -// - GetInputSourceName() [Internal] -// - DebugPrintInputEvent() [Internal] -// - UpdateInputEvents() [Internal] -//----------------------------------------------------------------------------- -// - GetKeyOwner() [Internal] -// - TestKeyOwner() [Internal] -// - SetKeyOwner() [Internal] -// - SetItemKeyOwner() [Internal] -// - Shortcut() [Internal] -//----------------------------------------------------------------------------- -ImGuiKeyData* ImGui::GetKeyData(ImGuiContext* ctx, ImGuiKey key) +// Test if mouse cursor is hovering given rectangle +// NB- Rectangle is clipped by our current clip setting +// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) +bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) +{ + ImGuiContext& g = *GImGui; + + // Clip + ImRect rect_clipped(r_min, r_max); + if (clip) + rect_clipped.ClipWith(g.CurrentWindow->ClipRect); + + // Expand for touch input + const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); + if (!rect_for_touch.Contains(g.IO.MousePos)) + return false; + return true; +} + +ImGuiKeyData* ImGui::GetKeyData(ImGuiKey key) { - ImGuiContext& g = *ctx; + ImGuiContext& g = *GImGui; // Special storage location for mods if (key & ImGuiMod_Mask_) - key = ConvertSingleModFlagToKey(ctx, key); + key = ConvertSingleModFlagToKey(key); + int index; #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO IM_ASSERT(key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_NamedKey_END); - if (IsLegacyKey(key) && g.IO.KeyMap[key] != -1) - key = (ImGuiKey)g.IO.KeyMap[key]; // Remap native->imgui or imgui->native + if (IsLegacyKey(key)) + index = (g.IO.KeyMap[key] != -1) ? g.IO.KeyMap[key] : key; // Remap native->imgui or imgui->native + else + index = key; #else IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend & user code."); + index = key - ImGuiKey_NamedKey_BEGIN; #endif - return &g.IO.KeysData[key - ImGuiKey_KeysData_OFFSET]; + return &g.IO.KeysData[index]; } #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO @@ -7960,34 +7936,31 @@ IM_STATIC_ASSERT(ImGuiKey_NamedKey_COUNT == IM_ARRAYSIZE(GKeyNames)); const char* ImGui::GetKeyName(ImGuiKey key) { - ImGuiContext& g = *GImGui; #ifdef IMGUI_DISABLE_OBSOLETE_KEYIO - IM_ASSERT((IsNamedKeyOrModKey(key) || key == ImGuiKey_None) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code."); + IM_ASSERT((IsNamedKey(key) || key == ImGuiKey_None) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code."); #else if (IsLegacyKey(key)) { - if (g.IO.KeyMap[key] == -1) + ImGuiIO& io = GetIO(); + if (io.KeyMap[key] == -1) return "N/A"; - IM_ASSERT(IsNamedKey((ImGuiKey)g.IO.KeyMap[key])); - key = (ImGuiKey)g.IO.KeyMap[key]; + IM_ASSERT(IsNamedKey((ImGuiKey)io.KeyMap[key])); + key = (ImGuiKey)io.KeyMap[key]; } #endif if (key == ImGuiKey_None) return "None"; if (key & ImGuiMod_Mask_) - key = ConvertSingleModFlagToKey(&g, key); + key = ConvertSingleModFlagToKey(key); if (!IsNamedKey(key)) return "Unknown"; return GKeyNames[key - ImGuiKey_NamedKey_BEGIN]; } -// ImGuiMod_Shortcut is translated to either Ctrl or Super. void ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size) { ImGuiContext& g = *GImGui; - if (key_chord & ImGuiMod_Shortcut) - key_chord = ConvertShortcutMod(key_chord); ImFormatString(out_buf, (size_t)out_buf_size, "%s%s%s%s%s", (key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "", (key_chord & ImGuiMod_Shift) ? "Shift+" : "", @@ -8038,52 +8011,13 @@ int ImGui::GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float repeat_ra } // Return 2D vector representing the combination of four cardinal direction, with analog value support (for e.g. ImGuiKey_GamepadLStick* values). -ImVec2 ImGui::GetKeyMagnitude2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down) +ImVec2 ImGui::GetKeyVector2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down) { return ImVec2( GetKeyData(key_right)->AnalogValue - GetKeyData(key_left)->AnalogValue, GetKeyData(key_down)->AnalogValue - GetKeyData(key_up)->AnalogValue); } -// Rewrite routing data buffers to strip old entries + sort by key to make queries not touch scattered data. -// Entries D,A,B,B,A,C,B --> A,A,B,B,B,C,D -// Index A:1 B:2 C:5 D:0 --> A:0 B:2 C:5 D:6 -// See 'Metrics->Key Owners & Shortcut Routing' to visualize the result of that operation. -static void ImGui::UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt) -{ - ImGuiContext& g = *GImGui; - rt->EntriesNext.resize(0); - for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) - { - const int new_routing_start_idx = rt->EntriesNext.Size; - ImGuiKeyRoutingData* routing_entry; - for (int old_routing_idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; old_routing_idx != -1; old_routing_idx = routing_entry->NextEntryIndex) - { - routing_entry = &rt->Entries[old_routing_idx]; - routing_entry->RoutingCurr = routing_entry->RoutingNext; // Update entry - routing_entry->RoutingNext = ImGuiKeyOwner_None; - routing_entry->RoutingNextScore = 255; - if (routing_entry->RoutingCurr == ImGuiKeyOwner_None) - continue; - rt->EntriesNext.push_back(*routing_entry); // Write alive ones into new buffer - - // Apply routing to owner if there's no owner already (RoutingCurr == None at this point) - if (routing_entry->Mods == g.IO.KeyMods) - { - ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); - if (owner_data->OwnerCurr == ImGuiKeyOwner_None) - owner_data->OwnerCurr = routing_entry->RoutingCurr; - } - } - - // Rewrite linked-list - rt->Index[key - ImGuiKey_NamedKey_BEGIN] = (ImGuiKeyRoutingIndex)(new_routing_start_idx < rt->EntriesNext.Size ? new_routing_start_idx : -1); - for (int n = new_routing_start_idx; n < rt->EntriesNext.Size; n++) - rt->EntriesNext[n].NextEntryIndex = (ImGuiKeyRoutingIndex)((n + 1 < rt->EntriesNext.Size) ? n + 1 : -1); - } - rt->Entries.swap(rt->EntriesNext); // Swap new and old indexes -} - // owner_id may be None/Any, but routing_id needs to be always be set, so we default to GetCurrentFocusScope(). static inline ImGuiID GetRoutingIdFromOwnerId(ImGuiID owner_id) { @@ -8102,12 +8036,10 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord) ImGuiContext& g = *GImGui; ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; ImGuiKeyRoutingData* routing_data; - if (key_chord & ImGuiMod_Shortcut) - key_chord = ConvertShortcutMod(key_chord); ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); if (key == ImGuiKey_None) - key = ConvertSingleModFlagToKey(&g, mods); + key = ConvertSingleModFlagToKey(mods); IM_ASSERT(IsNamedKey(key)); // Get (in the majority of case, the linked list will have one element so this should be 2 reads. @@ -8173,659 +8105,283 @@ static int CalcRoutingScore(ImGuiWindow* location, ImGuiID owner_id, ImGuiInputF return 2; if (flags & ImGuiInputFlags_RouteGlobalLow) return 254; - return 0; -} - -// Request a desired route for an input chord (key + mods). -// Return true if the route is available this frame. -// - Routes and key ownership are attributed at the beginning of next frame based on best score and mod state. -// (Conceptually this does a "Submit for next frame" + "Test for current frame". -// As such, it could be called TrySetXXX or SubmitXXX, or the Submit and Test operations should be separate.) -// - Using 'owner_id == ImGuiKeyOwner_Any/0': auto-assign an owner based on current focus scope (each window has its focus scope by default) -// - Using 'owner_id == ImGuiKeyOwner_None': allows disabling/locking a shortcut. -bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags) -{ - ImGuiContext& g = *GImGui; - if ((flags & ImGuiInputFlags_RouteMask_) == 0) - flags |= ImGuiInputFlags_RouteGlobalHigh; // IMPORTANT: This is the default for SetShortcutRouting() but NOT Shortcut() - else - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteMask_)); // Check that only 1 routing flag is used - - if (flags & ImGuiInputFlags_RouteUnlessBgFocused) - if (g.NavWindow == NULL) - return false; - if (flags & ImGuiInputFlags_RouteAlways) - return true; - - const int score = CalcRoutingScore(g.CurrentWindow, owner_id, flags); - if (score == 255) - return false; - - // Submit routing for NEXT frame (assuming score is sufficient) - // FIXME: Could expose a way to use a "serve last" policy for same score resolution (using <= instead of <). - ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); - const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id); - //const bool set_route = (flags & ImGuiInputFlags_ServeLast) ? (score <= routing_data->RoutingNextScore) : (score < routing_data->RoutingNextScore); - if (score < routing_data->RoutingNextScore) - { - routing_data->RoutingNext = routing_id; - routing_data->RoutingNextScore = (ImU8)score; - } - - // Return routing state for CURRENT frame - return routing_data->RoutingCurr == routing_id; -} - -// Currently unused by core (but used by tests) -// Note: this cannot be turned into GetShortcutRouting() because we do the owner_id->routing_id translation, name would be more misleading. -bool ImGui::TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id) -{ - const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id); - ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); // FIXME: Could avoid creating entry. - return routing_data->RoutingCurr == routing_id; -} - -// Note that Dear ImGui doesn't know the meaning/semantic of ImGuiKey from 0..511: they are legacy native keycodes. -// Consider transitioning from 'IsKeyDown(MY_ENGINE_KEY_A)' (<1.87) to IsKeyDown(ImGuiKey_A) (>= 1.87) -bool ImGui::IsKeyDown(ImGuiKey key) -{ - return IsKeyDown(key, ImGuiKeyOwner_Any); -} - -bool ImGui::IsKeyDown(ImGuiKey key, ImGuiID owner_id) -{ - const ImGuiKeyData* key_data = GetKeyData(key); - if (!key_data->Down) - return false; - if (!TestKeyOwner(key, owner_id)) - return false; - return true; -} - -bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat) -{ - return IsKeyPressed(key, ImGuiKeyOwner_Any, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None); -} - -// Important: unless legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat. -bool ImGui::IsKeyPressed(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags) -{ - const ImGuiKeyData* key_data = GetKeyData(key); - if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership) - return false; - const float t = key_data->DownDuration; - if (t < 0.0f) - return false; - IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function! - - bool pressed = (t == 0.0f); - if (!pressed && ((flags & ImGuiInputFlags_Repeat) != 0)) - { - float repeat_delay, repeat_rate; - GetTypematicRepeatRate(flags, &repeat_delay, &repeat_rate); - pressed = (t > repeat_delay) && GetKeyPressedAmount(key, repeat_delay, repeat_rate) > 0; - } - if (!pressed) - return false; - if (!TestKeyOwner(key, owner_id)) - return false; - return true; -} - -bool ImGui::IsKeyReleased(ImGuiKey key) -{ - return IsKeyReleased(key, ImGuiKeyOwner_Any); -} - -bool ImGui::IsKeyReleased(ImGuiKey key, ImGuiID owner_id) -{ - const ImGuiKeyData* key_data = GetKeyData(key); - if (key_data->DownDurationPrev < 0.0f || key_data->Down) - return false; - if (!TestKeyOwner(key, owner_id)) - return false; - return true; -} - -bool ImGui::IsMouseDown(ImGuiMouseButton button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // should be same as IsKeyDown(MouseButtonToKey(button), ImGuiKeyOwner_Any), but this allows legacy code hijacking the io.Mousedown[] array. -} - -bool ImGui::IsMouseDown(ImGuiMouseButton button, ImGuiID owner_id) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyDown(MouseButtonToKey(button), owner_id), but this allows legacy code hijacking the io.Mousedown[] array. -} - -bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat) -{ - return IsMouseClicked(button, ImGuiKeyOwner_Any, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None); -} - -bool ImGui::IsMouseClicked(ImGuiMouseButton button, ImGuiID owner_id, ImGuiInputFlags flags) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - if (!g.IO.MouseDown[button]) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership) - return false; - const float t = g.IO.MouseDownDuration[button]; - if (t < 0.0f) - return false; - IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function! - - const bool repeat = (flags & ImGuiInputFlags_Repeat) != 0; - const bool pressed = (t == 0.0f) || (repeat && t > g.IO.KeyRepeatDelay && CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0); - if (!pressed) - return false; - - if (!TestKeyOwner(MouseButtonToKey(button), owner_id)) - return false; - - return true; -} - -bool ImGui::IsMouseReleased(ImGuiMouseButton button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // Should be same as IsKeyReleased(MouseButtonToKey(button), ImGuiKeyOwner_Any) -} - -bool ImGui::IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyReleased(MouseButtonToKey(button), owner_id) -} - -bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseClickedCount[button] == 2 && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); -} - -int ImGui::GetMouseClickedCount(ImGuiMouseButton button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseClickedCount[button]; -} - -// Test if mouse cursor is hovering given rectangle -// NB- Rectangle is clipped by our current clip setting -// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) -bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) -{ - ImGuiContext& g = *GImGui; - - // Clip - ImRect rect_clipped(r_min, r_max); - if (clip) - rect_clipped.ClipWith(g.CurrentWindow->ClipRect); - - // Expand for touch input - const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); - if (!rect_for_touch.Contains(g.IO.MousePos)) - return false; - return true; -} - -// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame. -// [Internal] This doesn't test if the button is pressed -bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - if (lock_threshold < 0.0f) - lock_threshold = g.IO.MouseDragThreshold; - return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; + return 0; } -bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold) +// Request a desired route for an input chord (key + mods). +// Return true if the route is available this frame. +// - Routes and key ownership are attributed at the beginning of next frame based on best score and mod state. +// (Conceptually this does a "Submit for next frame" + "Test for current frame". +// As such, it could be called TrySetXXX or SubmitXXX, or the Submit and Test operations should be separate.) +// - Using 'owner_id == ImGuiKeyOwner_Any/0': auto-assign an owner based on current focus scope (each window has its focus scope by default) +// - Using 'owner_id == ImGuiKeyOwner_None': allows disabling/locking a shortcut. +bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags) { ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - if (!g.IO.MouseDown[button]) + if ((flags & ImGuiInputFlags_RouteMask_) == 0) + flags |= ImGuiInputFlags_RouteGlobalHigh; // IMPORTANT: This is the default for SetShortcutRouting() but NOT Shortcut() + else + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteMask_)); // Check that only 1 routing flag is used + + if (flags & ImGuiInputFlags_RouteUnlessBgFocused) + if (g.NavWindow == NULL) + return false; + if (flags & ImGuiInputFlags_RouteAlways) + return true; + + const int score = CalcRoutingScore(g.CurrentWindow, owner_id, flags); + if (score == 255) return false; - return IsMouseDragPastThreshold(button, lock_threshold); -} -ImVec2 ImGui::GetMousePos() -{ - ImGuiContext& g = *GImGui; - return g.IO.MousePos; -} + // Submit routing for NEXT frame (assuming score is sufficient) + // FIXME: Could expose a way to use a "serve last" policy for same score resolution (using <= instead of <). + ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); + const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id); + //const bool set_route = (flags & ImGuiInputFlags_ServeLast) ? (score <= routing_data->RoutingNextScore) : (score < routing_data->RoutingNextScore); + if (score < routing_data->RoutingNextScore) + { + routing_data->RoutingNext = routing_id; + routing_data->RoutingNextScore = (ImU8)score; + } -// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! -ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() -{ - ImGuiContext& g = *GImGui; - if (g.BeginPopupStack.Size > 0) - return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; - return g.IO.MousePos; + // Return routing state for CURRENT frame + return routing_data->RoutingCurr == routing_id; } -// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. -bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) +// Currently unused by core (but used by tests) +// Note: this cannot be turned into GetShortcutRouting() because we do the owner_id->routing_id translation, name would be more misleading. +bool ImGui::TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id) { - // The assert is only to silence a false-positive in XCode Static Analysis. - // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). - IM_ASSERT(GImGui != NULL); - const float MOUSE_INVALID = -256000.0f; - ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; - return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; + const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id); + ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); + return routing_data->RoutingCurr == routing_id; } -// [WILL OBSOLETE] This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid. -bool ImGui::IsAnyMouseDown() +// Note that Dear ImGui doesn't know the meaning/semantic of ImGuiKey from 0..511: they are legacy native keycodes. +// Consider transitioning from 'IsKeyDown(MY_ENGINE_KEY_A)' (<1.87) to IsKeyDown(ImGuiKey_A) (>= 1.87) +bool ImGui::IsKeyDown(ImGuiKey key) { - ImGuiContext& g = *GImGui; - for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) - if (g.IO.MouseDown[n]) - return true; - return false; + return IsKeyDown(key, ImGuiKeyOwner_Any); } -// Return the delta from the initial clicking position while the mouse button is clicked or was just released. -// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. -// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window. -ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold) +bool ImGui::IsKeyDown(ImGuiKey key, ImGuiID owner_id) { - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - if (lock_threshold < 0.0f) - lock_threshold = g.IO.MouseDragThreshold; - if (g.IO.MouseDown[button] || g.IO.MouseReleased[button]) - if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) - if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button])) - return g.IO.MousePos - g.IO.MouseClickedPos[button]; - return ImVec2(0.0f, 0.0f); + const ImGuiKeyData* key_data = GetKeyData(key); + if (!key_data->Down) + return false; + if (!TestKeyOwner(key, owner_id)) + return false; + return true; } -void ImGui::ResetMouseDragDelta(ImGuiMouseButton button) +bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat) { - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr - g.IO.MouseClickedPos[button] = g.IO.MousePos; + return IsKeyPressed(key, ImGuiKeyOwner_Any, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None); } -// Get desired mouse cursor shape. -// Important: this is meant to be used by a platform backend, it is reset in ImGui::NewFrame(), -// updated during the frame, and locked in EndFrame()/Render(). -// If you use software rendering by setting io.MouseDrawCursor then Dear ImGui will render those for you -ImGuiMouseCursor ImGui::GetMouseCursor() +// Important: unless legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat. +bool ImGui::IsKeyPressed(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags) { - ImGuiContext& g = *GImGui; - return g.MouseCursor; + const ImGuiKeyData* key_data = GetKeyData(key); + if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership) + return false; + const float t = key_data->DownDuration; + if (t < 0.0f) + return false; + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function! + + bool pressed = (t == 0.0f); + if (!pressed && ((flags & ImGuiInputFlags_Repeat) != 0)) + { + float repeat_delay, repeat_rate; + GetTypematicRepeatRate(flags, &repeat_delay, &repeat_rate); + pressed = (t > repeat_delay) && GetKeyPressedAmount(key, repeat_delay, repeat_rate) > 0; + } + if (!pressed) + return false; + if (!TestKeyOwner(key, owner_id)) + return false; + return true; } -void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) +bool ImGui::IsKeyReleased(ImGuiKey key) { - ImGuiContext& g = *GImGui; - g.MouseCursor = cursor_type; + return IsKeyReleased(key, ImGuiKeyOwner_Any); } -static void UpdateAliasKey(ImGuiKey key, bool v, float analog_value) +bool ImGui::IsKeyReleased(ImGuiKey key, ImGuiID owner_id) { - IM_ASSERT(ImGui::IsAliasKey(key)); - ImGuiKeyData* key_data = ImGui::GetKeyData(key); - key_data->Down = v; - key_data->AnalogValue = analog_value; + const ImGuiKeyData* key_data = GetKeyData(key); + if (key_data->DownDurationPrev < 0.0f || key_data->Down) + return false; + if (!TestKeyOwner(key, owner_id)) + return false; + return true; } -// [Internal] Do not use directly -static ImGuiKeyChord GetMergedModsFromKeys() +bool ImGui::IsMouseDown(ImGuiMouseButton button) { - ImGuiKeyChord mods = 0; - if (ImGui::IsKeyDown(ImGuiMod_Ctrl)) { mods |= ImGuiMod_Ctrl; } - if (ImGui::IsKeyDown(ImGuiMod_Shift)) { mods |= ImGuiMod_Shift; } - if (ImGui::IsKeyDown(ImGuiMod_Alt)) { mods |= ImGuiMod_Alt; } - if (ImGui::IsKeyDown(ImGuiMod_Super)) { mods |= ImGuiMod_Super; } - return mods; + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // should be same as IsKeyDown(MouseButtonToKey(button), ImGuiKeyOwner_Any), but this allows legacy code hijacking the io.Mousedown[] array. } -static void ImGui::UpdateKeyboardInputs() +bool ImGui::IsMouseDown(ImGuiMouseButton button, ImGuiID owner_id) { ImGuiContext& g = *GImGui; - ImGuiIO& io = g.IO; - - // Import legacy keys or verify they are not used -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - if (io.BackendUsingLegacyKeyArrays == 0) - { - // Backend used new io.AddKeyEvent() API: Good! Verify that old arrays are never written to externally. - for (int n = 0; n < ImGuiKey_LegacyNativeKey_END; n++) - IM_ASSERT((io.KeysDown[n] == false || IsKeyDown((ImGuiKey)n)) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); - } - else - { - if (g.FrameCount == 0) - for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) - IM_ASSERT(g.IO.KeyMap[n] == -1 && "Backend is not allowed to write to io.KeyMap[0..511]!"); - - // Build reverse KeyMap (Named -> Legacy) - for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++) - if (io.KeyMap[n] != -1) - { - IM_ASSERT(IsLegacyKey((ImGuiKey)io.KeyMap[n])); - io.KeyMap[io.KeyMap[n]] = n; - } - - // Import legacy keys into new ones - for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) - if (io.KeysDown[n] || io.BackendUsingLegacyKeyArrays == 1) - { - const ImGuiKey key = (ImGuiKey)(io.KeyMap[n] != -1 ? io.KeyMap[n] : n); - IM_ASSERT(io.KeyMap[n] == -1 || IsNamedKey(key)); - io.KeysData[key].Down = io.KeysDown[n]; - if (key != n) - io.KeysDown[key] = io.KeysDown[n]; // Allow legacy code using io.KeysDown[GetKeyIndex()] with old backends - io.BackendUsingLegacyKeyArrays = 1; - } - if (io.BackendUsingLegacyKeyArrays == 1) - { - GetKeyData(ImGuiMod_Ctrl)->Down = io.KeyCtrl; - GetKeyData(ImGuiMod_Shift)->Down = io.KeyShift; - GetKeyData(ImGuiMod_Alt)->Down = io.KeyAlt; - GetKeyData(ImGuiMod_Super)->Down = io.KeySuper; - } - } - -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; - if (io.BackendUsingLegacyNavInputArray && nav_gamepad_active) - { - #define MAP_LEGACY_NAV_INPUT_TO_KEY1(_KEY, _NAV1) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f); io.KeysData[_KEY].AnalogValue = io.NavInputs[_NAV1]; } while (0) - #define MAP_LEGACY_NAV_INPUT_TO_KEY2(_KEY, _NAV1, _NAV2) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f) || (io.NavInputs[_NAV2] > 0.0f); io.KeysData[_KEY].AnalogValue = ImMax(io.NavInputs[_NAV1], io.NavInputs[_NAV2]); } while (0) - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceDown, ImGuiNavInput_Activate); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceRight, ImGuiNavInput_Cancel); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceLeft, ImGuiNavInput_Menu); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceUp, ImGuiNavInput_Input); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadLeft, ImGuiNavInput_DpadLeft); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadRight, ImGuiNavInput_DpadRight); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadUp, ImGuiNavInput_DpadUp); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadDown, ImGuiNavInput_DpadDown); - MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadL1, ImGuiNavInput_FocusPrev, ImGuiNavInput_TweakSlow); - MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadR1, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakFast); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickLeft, ImGuiNavInput_LStickLeft); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickRight, ImGuiNavInput_LStickRight); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickUp, ImGuiNavInput_LStickUp); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickDown, ImGuiNavInput_LStickDown); - #undef NAV_MAP_KEY - } -#endif -#endif - - // Update aliases - for (int n = 0; n < ImGuiMouseButton_COUNT; n++) - UpdateAliasKey(MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] ? 1.0f : 0.0f); - UpdateAliasKey(ImGuiKey_MouseWheelX, io.MouseWheelH != 0.0f, io.MouseWheelH); - UpdateAliasKey(ImGuiKey_MouseWheelY, io.MouseWheel != 0.0f, io.MouseWheel); - - // Synchronize io.KeyMods and io.KeyXXX values. - // - New backends (1.87+): send io.AddKeyEvent(ImGuiMod_XXX) -> -> (here) deriving io.KeyMods + io.KeyXXX from key array. - // - Legacy backends: set io.KeyXXX bools -> (above) set key array from io.KeyXXX -> (here) deriving io.KeyMods + io.KeyXXX from key array. - // So with legacy backends the 4 values will do a unnecessary back-and-forth but it makes the code simpler and future facing. - io.KeyMods = GetMergedModsFromKeys(); - io.KeyCtrl = (io.KeyMods & ImGuiMod_Ctrl) != 0; - io.KeyShift = (io.KeyMods & ImGuiMod_Shift) != 0; - io.KeyAlt = (io.KeyMods & ImGuiMod_Alt) != 0; - io.KeySuper = (io.KeyMods & ImGuiMod_Super) != 0; - - // Clear gamepad data if disabled - if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0) - for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++) - { - io.KeysData[i - ImGuiKey_KeysData_OFFSET].Down = false; - io.KeysData[i - ImGuiKey_KeysData_OFFSET].AnalogValue = 0.0f; - } - - // Update keys - for (int i = 0; i < ImGuiKey_KeysData_SIZE; i++) - { - ImGuiKeyData* key_data = &io.KeysData[i]; - key_data->DownDurationPrev = key_data->DownDuration; - key_data->DownDuration = key_data->Down ? (key_data->DownDuration < 0.0f ? 0.0f : key_data->DownDuration + io.DeltaTime) : -1.0f; - } - - // Update keys/input owner (named keys only): one entry per key - for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) - { - ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_KeysData_OFFSET]; - ImGuiKeyOwnerData* owner_data = &g.KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; - owner_data->OwnerCurr = owner_data->OwnerNext; - if (!key_data->Down) // Important: ownership is released on the frame after a release. Ensure a 'MouseDown -> CloseWindow -> MouseUp' chain doesn't lead to someone else seeing the MouseUp. - owner_data->OwnerNext = ImGuiKeyOwner_None; - owner_data->LockThisFrame = owner_data->LockUntilRelease = owner_data->LockUntilRelease && key_data->Down; // Clear LockUntilRelease when key is not Down anymore - } + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyDown(MouseButtonToKey(button), owner_id), but this allows legacy code hijacking the io.Mousedown[] array. +} - UpdateKeyRoutingTable(&g.KeysRoutingTable); +bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat) +{ + return IsMouseClicked(button, ImGuiKeyOwner_Any, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None); } -static void ImGui::UpdateMouseInputs() +bool ImGui::IsMouseClicked(ImGuiMouseButton button, ImGuiID owner_id, ImGuiInputFlags flags) { ImGuiContext& g = *GImGui; - ImGuiIO& io = g.IO; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (!g.IO.MouseDown[button]) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership) + return false; + const float t = g.IO.MouseDownDuration[button]; + if (t < 0.0f) + return false; + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function! - // Mouse Wheel swapping flag - // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead - // - We avoid doing it on OSX as it the OS input layer handles this already. - // - FIXME: However this means when running on OSX over Emscripten, Shift+WheelY will incur two swapping (1 in OS, 1 here), canceling the feature. - // - FIXME: When we can distinguish e.g. touchpad scroll events from mouse ones, we'll set this accordingly based on input source. - io.MouseWheelRequestAxisSwap = io.KeyShift && !io.ConfigMacOSXBehaviors; + const bool repeat = (flags & ImGuiInputFlags_Repeat) != 0; + const bool pressed = (t == 0.0f) || (repeat && t > g.IO.KeyRepeatDelay && CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0); + if (!pressed) + return false; - // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) - if (IsMousePosValid(&io.MousePos)) - io.MousePos = g.MouseLastValidPos = ImFloorSigned(io.MousePos); + if (!TestKeyOwner(MouseButtonToKey(button), owner_id)) + return false; - // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta - if (IsMousePosValid(&io.MousePos) && IsMousePosValid(&io.MousePosPrev)) - io.MouseDelta = io.MousePos - io.MousePosPrev; - else - io.MouseDelta = ImVec2(0.0f, 0.0f); + return true; +} - // Update stationary timer. - // FIXME: May need to rework again to have some tolerance for occasional small movement, while being functional on high-framerates. - const float mouse_stationary_threshold = (io.MouseSource == ImGuiMouseSource_Mouse) ? 2.0f : 3.0f; // Slightly higher threshold for ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen, may need rework. - const bool mouse_stationary = (ImLengthSqr(io.MouseDelta) <= mouse_stationary_threshold * mouse_stationary_threshold); - g.MouseStationaryTimer = mouse_stationary ? (g.MouseStationaryTimer + io.DeltaTime) : 0.0f; - //IMGUI_DEBUG_LOG("%.4f\n", g.MouseStationaryTimer); +bool ImGui::IsMouseReleased(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // Should be same as IsKeyReleased(MouseButtonToKey(button), ImGuiKeyOwner_Any) +} - // If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. - if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) - g.NavDisableMouseHover = false; +bool ImGui::IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyReleased(MouseButtonToKey(button), owner_id) +} - io.MousePosPrev = io.MousePos; - for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) - { - io.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f; - io.MouseClickedCount[i] = 0; // Will be filled below - io.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0f; - io.MouseDownDurationPrev[i] = io.MouseDownDuration[i]; - io.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0.0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f; - if (io.MouseClicked[i]) - { - bool is_repeated_click = false; - if ((float)(g.Time - io.MouseClickedTime[i]) < io.MouseDoubleClickTime) - { - ImVec2 delta_from_click_pos = IsMousePosValid(&io.MousePos) ? (io.MousePos - io.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); - if (ImLengthSqr(delta_from_click_pos) < io.MouseDoubleClickMaxDist * io.MouseDoubleClickMaxDist) - is_repeated_click = true; - } - if (is_repeated_click) - io.MouseClickedLastCount[i]++; - else - io.MouseClickedLastCount[i] = 1; - io.MouseClickedTime[i] = g.Time; - io.MouseClickedPos[i] = io.MousePos; - io.MouseClickedCount[i] = io.MouseClickedLastCount[i]; - io.MouseDragMaxDistanceSqr[i] = 0.0f; - } - else if (io.MouseDown[i]) - { - // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold - float delta_sqr_click_pos = IsMousePosValid(&io.MousePos) ? ImLengthSqr(io.MousePos - io.MouseClickedPos[i]) : 0.0f; - io.MouseDragMaxDistanceSqr[i] = ImMax(io.MouseDragMaxDistanceSqr[i], delta_sqr_click_pos); - } +bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseClickedCount[button] == 2 && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); +} - // We provide io.MouseDoubleClicked[] as a legacy service - io.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2); +int ImGui::GetMouseClickedCount(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseClickedCount[button]; +} - // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation - if (io.MouseClicked[i]) - g.NavDisableMouseHover = false; - } +// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame. +// [Internal] This doesn't test if the button is pressed +bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; } -static void LockWheelingWindow(ImGuiWindow* window, float wheel_amount) +bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold) { ImGuiContext& g = *GImGui; - if (window) - g.WheelingWindowReleaseTimer = ImMin(g.WheelingWindowReleaseTimer + ImAbs(wheel_amount) * WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER, WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER); - else - g.WheelingWindowReleaseTimer = 0.0f; - if (g.WheelingWindow == window) - return; - IMGUI_DEBUG_LOG_IO("[io] LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL"); - g.WheelingWindow = window; - g.WheelingWindowRefMousePos = g.IO.MousePos; - if (window == NULL) - { - g.WheelingWindowStartFrame = -1; - g.WheelingAxisAvg = ImVec2(0.0f, 0.0f); - } + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (!g.IO.MouseDown[button]) + return false; + return IsMouseDragPastThreshold(button, lock_threshold); } -static ImGuiWindow* FindBestWheelingWindow(const ImVec2& wheel) +ImVec2 ImGui::GetMousePos() { - // For each axis, find window in the hierarchy that may want to use scrolling ImGuiContext& g = *GImGui; - ImGuiWindow* windows[2] = { NULL, NULL }; - for (int axis = 0; axis < 2; axis++) - if (wheel[axis] != 0.0f) - for (ImGuiWindow* window = windows[axis] = g.HoveredWindow; window->Flags & ImGuiWindowFlags_ChildWindow; window = windows[axis] = window->ParentWindow) - { - // Bubble up into parent window if: - // - a child window doesn't allow any scrolling. - // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag. - //// - a child window doesn't need scrolling because it is already at the edge for the direction we are going in (FIXME-WIP) - const bool has_scrolling = (window->ScrollMax[axis] != 0.0f); - const bool inputs_disabled = (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs); - //const bool scrolling_past_limits = (wheel_v < 0.0f) ? (window->Scroll[axis] <= 0.0f) : (window->Scroll[axis] >= window->ScrollMax[axis]); - if (has_scrolling && !inputs_disabled) // && !scrolling_past_limits) - break; // select this window - } - if (windows[0] == NULL && windows[1] == NULL) - return NULL; + return g.IO.MousePos; +} - // If there's only one window or only one axis then there's no ambiguity - if (windows[0] == windows[1] || windows[0] == NULL || windows[1] == NULL) - return windows[1] ? windows[1] : windows[0]; +// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! +ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() +{ + ImGuiContext& g = *GImGui; + if (g.BeginPopupStack.Size > 0) + return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; + return g.IO.MousePos; +} - // If candidate are different windows we need to decide which one to prioritize - // - First frame: only find a winner if one axis is zero. - // - Subsequent frames: only find a winner when one is more than the other. - if (g.WheelingWindowStartFrame == -1) - g.WheelingWindowStartFrame = g.FrameCount; - if ((g.WheelingWindowStartFrame == g.FrameCount && wheel.x != 0.0f && wheel.y != 0.0f) || (g.WheelingAxisAvg.x == g.WheelingAxisAvg.y)) - { - g.WheelingWindowWheelRemainder = wheel; - return NULL; - } - return (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? windows[0] : windows[1]; +// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. +bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) +{ + // The assert is only to silence a false-positive in XCode Static Analysis. + // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). + IM_ASSERT(GImGui != NULL); + const float MOUSE_INVALID = -256000.0f; + ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; + return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; } -// Called by NewFrame() -void ImGui::UpdateMouseWheel() +// [WILL OBSOLETE] This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid. +bool ImGui::IsAnyMouseDown() { - // Reset the locked window if we move the mouse or after the timer elapses. - // FIXME: Ideally we could refactor to have one timer for "changing window w/ same axis" and a shorter timer for "changing window or axis w/ other axis" (#3795) ImGuiContext& g = *GImGui; - if (g.WheelingWindow != NULL) - { - g.WheelingWindowReleaseTimer -= g.IO.DeltaTime; - if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold) - g.WheelingWindowReleaseTimer = 0.0f; - if (g.WheelingWindowReleaseTimer <= 0.0f) - LockWheelingWindow(NULL, 0.0f); - } - - ImVec2 wheel; - wheel.x = TestKeyOwner(ImGuiKey_MouseWheelX, ImGuiKeyOwner_None) ? g.IO.MouseWheelH : 0.0f; - wheel.y = TestKeyOwner(ImGuiKey_MouseWheelY, ImGuiKeyOwner_None) ? g.IO.MouseWheel : 0.0f; + for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) + if (g.IO.MouseDown[n]) + return true; + return false; +} - //IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y); - ImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow; - if (!mouse_window || mouse_window->Collapsed) - return; +// Return the delta from the initial clicking position while the mouse button is clicked or was just released. +// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. +// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window. +ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + if (g.IO.MouseDown[button] || g.IO.MouseReleased[button]) + if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) + if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button])) + return g.IO.MousePos - g.IO.MouseClickedPos[button]; + return ImVec2(0.0f, 0.0f); +} - // Zoom / Scale window - // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned. - if (wheel.y != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling) - { - LockWheelingWindow(mouse_window, wheel.y); - ImGuiWindow* window = mouse_window; - const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); - const float scale = new_font_scale / window->FontWindowScale; - window->FontWindowScale = new_font_scale; - if (window == window->RootWindow) - { - const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; - SetWindowPos(window, window->Pos + offset, 0); - window->Size = ImFloor(window->Size * scale); - window->SizeFull = ImFloor(window->SizeFull * scale); - } - return; - } - if (g.IO.KeyCtrl) - return; +void ImGui::ResetMouseDragDelta(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr + g.IO.MouseClickedPos[button] = g.IO.MousePos; +} - // Mouse wheel scrolling - // Read about io.MouseWheelRequestAxisSwap and its issue on Mac+Emscripten in UpdateMouseInputs() - if (g.IO.MouseWheelRequestAxisSwap) - wheel = ImVec2(wheel.y, 0.0f); - - // Maintain a rough average of moving magnitude on both axises - // FIXME: should by based on wall clock time rather than frame-counter - g.WheelingAxisAvg.x = ImExponentialMovingAverage(g.WheelingAxisAvg.x, ImAbs(wheel.x), 30); - g.WheelingAxisAvg.y = ImExponentialMovingAverage(g.WheelingAxisAvg.y, ImAbs(wheel.y), 30); - - // In the rare situation where FindBestWheelingWindow() had to defer first frame of wheeling due to ambiguous main axis, reinject it now. - wheel += g.WheelingWindowWheelRemainder; - g.WheelingWindowWheelRemainder = ImVec2(0.0f, 0.0f); - if (wheel.x == 0.0f && wheel.y == 0.0f) - return; +// Get desired mouse cursor shape. +// Important: this is meant to be used by a platform backend, it is reset in ImGui::NewFrame(), +// updated during the frame, and locked in EndFrame()/Render(). +// If you use software rendering by setting io.MouseDrawCursor then Dear ImGui will render those for you +ImGuiMouseCursor ImGui::GetMouseCursor() +{ + ImGuiContext& g = *GImGui; + return g.MouseCursor; +} - // Mouse wheel scrolling: find target and apply - // - don't renew lock if axis doesn't apply on the window. - // - select a main axis when both axises are being moved. - if (ImGuiWindow* window = (g.WheelingWindow ? g.WheelingWindow : FindBestWheelingWindow(wheel))) - if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) - { - bool do_scroll[2] = { wheel.x != 0.0f && window->ScrollMax.x != 0.0f, wheel.y != 0.0f && window->ScrollMax.y != 0.0f }; - if (do_scroll[ImGuiAxis_X] && do_scroll[ImGuiAxis_Y]) - do_scroll[(g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? ImGuiAxis_Y : ImGuiAxis_X] = false; - if (do_scroll[ImGuiAxis_X]) - { - LockWheelingWindow(window, wheel.x); - float max_step = window->InnerRect.GetWidth() * 0.67f; - float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step)); - SetScrollX(window, window->Scroll.x - wheel.x * scroll_step); - } - if (do_scroll[ImGuiAxis_Y]) - { - LockWheelingWindow(window, wheel.y); - float max_step = window->InnerRect.GetHeight() * 0.67f; - float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step)); - SetScrollY(window, window->Scroll.y - wheel.y * scroll_step); - } - } +void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) +{ + ImGuiContext& g = *GImGui; + g.MouseCursor = cursor_type; } void ImGui::SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard) @@ -8843,25 +8399,19 @@ void ImGui::SetNextFrameWantCaptureMouse(bool want_capture_mouse) #ifndef IMGUI_DISABLE_DEBUG_TOOLS static const char* GetInputSourceName(ImGuiInputSource source) { - const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Clipboard" }; + const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT); return input_source_names[source]; } -static const char* GetMouseSourceName(ImGuiMouseSource source) -{ - const char* mouse_source_names[] = { "Mouse", "TouchScreen", "Pen" }; - IM_ASSERT(IM_ARRAYSIZE(mouse_source_names) == ImGuiMouseSource_COUNT && source >= 0 && source < ImGuiMouseSource_COUNT); - return mouse_source_names[source]; -} static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e) { ImGuiContext& g = *GImGui; - if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; } - if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseWheel.MouseSource)); return; } - if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseWheel (%.3f, %.3f) (%s)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; } - if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("[io] %s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; } - if (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO("[io] %s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; } - if (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO("[io] %s: AppFocused %d\n", prefix, e->AppFocused.Focused); return; } + if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("%s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("%s: MousePos (%.1f, %.1f)\n", prefix, e->MousePos.PosX, e->MousePos.PosY); return; } + if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("%s: MouseButton %d %s\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up"); return; } + if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("%s: MouseWheel (%.1f, %.1f)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY); return; } + if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("%s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; } + if (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO("%s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; } + if (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO("%s: AppFocused %d\n", prefix, e->AppFocused.Focused); return; } } #endif @@ -8894,7 +8444,6 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted)) break; io.MousePos = event_pos; - io.MouseSource = e->MousePos.MouseSource; mouse_moved = true; } else if (e->Type == ImGuiInputEventType_MouseButton) @@ -8904,10 +8453,7 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT); if (trickle_fast_inputs && ((mouse_button_changed & (1 << button)) || mouse_wheeled)) break; - if (trickle_fast_inputs && e->MouseButton.MouseSource == ImGuiMouseSource_TouchScreen && mouse_moved) // #2702: TouchScreen have no initial hover. - break; io.MouseDown[button] = e->MouseButton.Down; - io.MouseSource = e->MouseButton.MouseSource; mouse_button_changed |= (1 << button); } else if (e->Type == ImGuiInputEventType_MouseWheel) @@ -8917,7 +8463,6 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) break; io.MouseWheelH += e->MouseWheel.WheelX; io.MouseWheel += e->MouseWheel.WheelY; - io.MouseSource = e->MouseWheel.MouseSource; mouse_wheeled = true; } else if (e->Type == ImGuiInputEventType_Key) @@ -8934,6 +8479,15 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) key_changed = true; key_changed_mask.SetBit(key_data_index); + if (key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super) + { + if (key == ImGuiMod_Ctrl) { io.KeyCtrl = key_data->Down; } + if (key == ImGuiMod_Shift) { io.KeyShift = key_data->Down; } + if (key == ImGuiMod_Alt) { io.KeyAlt = key_data->Down; } + if (key == ImGuiMod_Super) { io.KeySuper = key_data->Down; } + io.KeyMods = GetMergedModsFromBools(); + } + // Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO io.KeysDown[key_data_index] = key_data->Down; @@ -8996,7 +8550,7 @@ ImGuiID ImGui::GetKeyOwner(ImGuiKey key) return ImGuiKeyOwner_None; ImGuiContext& g = *GImGui; - ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); ImGuiID owner_id = owner_data->OwnerCurr; if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any) @@ -9020,7 +8574,7 @@ bool ImGui::TestKeyOwner(ImGuiKey key, ImGuiID owner_id) if (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END) return false; - ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); if (owner_id == ImGuiKeyOwner_Any) return (owner_data->LockThisFrame == false); @@ -9048,8 +8602,7 @@ void ImGui::SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags) IM_ASSERT(IsNamedKeyOrModKey(key) && (owner_id != ImGuiKeyOwner_Any || (flags & (ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease)))); // Can only use _Any with _LockXXX flags (to eat a key away without an ID to retrieve it) IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetKeyOwner) == 0); // Passing flags not supported by this function! - ImGuiContext& g = *GImGui; - ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); owner_data->OwnerCurr = owner_data->OwnerNext = owner_id; // We cannot lock by default as it would likely break lots of legacy code. @@ -9058,17 +8611,6 @@ void ImGui::SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags) owner_data->LockThisFrame = (flags & ImGuiInputFlags_LockThisFrame) != 0 || (owner_data->LockUntilRelease); } -// Rarely used helper -void ImGui::SetKeyOwnersForKeyChord(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags) -{ - if (key_chord & ImGuiMod_Ctrl) { SetKeyOwner(ImGuiMod_Ctrl, owner_id, flags); } - if (key_chord & ImGuiMod_Shift) { SetKeyOwner(ImGuiMod_Shift, owner_id, flags); } - if (key_chord & ImGuiMod_Alt) { SetKeyOwner(ImGuiMod_Alt, owner_id, flags); } - if (key_chord & ImGuiMod_Super) { SetKeyOwner(ImGuiMod_Super, owner_id, flags); } - if (key_chord & ImGuiMod_Shortcut) { SetKeyOwner(ImGuiMod_Shortcut, owner_id, flags); } - if (key_chord & ~ImGuiMod_Mask_) { SetKeyOwner((ImGuiKey)(key_chord & ~ImGuiMod_Mask_), owner_id, flags); } -} - // This is more or less equivalent to: // if (IsItemHovered() || IsItemActive()) // SetKeyOwner(key, GetItemID()); @@ -9090,6 +8632,8 @@ void ImGui::SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags) } } +// - Need to decide how to handle shortcut translations for Non-Mac <> Mac +// - Ideas: https://github.com/ocornut/imgui/issues/456#issuecomment-264390864 bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags) { ImGuiContext& g = *GImGui; @@ -9100,18 +8644,16 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags if (!SetShortcutRouting(key_chord, owner_id, flags)) return false; - if (key_chord & ImGuiMod_Shortcut) - key_chord = ConvertShortcutMod(key_chord); + ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); if (g.IO.KeyMods != mods) return false; // Special storage location for mods - ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); if (key == ImGuiKey_None) - key = ConvertSingleModFlagToKey(&g, mods); + key = ConvertSingleModFlagToKey(mods); - if (!IsKeyPressed(key, owner_id, (flags & (ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateMask_)))) + if (!IsKeyPressed(key, owner_id, (flags & (ImGuiInputFlags_Repeat | ImGuiInputFlags_RepeatRateMask_)))) return false; IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByShortcut) == 0); // Passing flags not supported by this function! @@ -9186,14 +8728,7 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() // This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.) // #define IM_ASSERT(EXPR) if (SomeCode(EXPR)) SomeMoreCode(); // Wrong! // #define IM_ASSERT(EXPR) do { if (SomeCode(EXPR)) SomeMoreCode(); } while (0) // Correct! - if (true) IM_ASSERT(1); else IM_ASSERT(0); - - // Emscripten backends are often imprecise in their submission of DeltaTime. (#6114, #3644) - // Ideally the Emscripten app/backend should aim to fix or smooth this value and avoid feeding zero, but we tolerate it. -#ifdef __EMSCRIPTEN__ - if (g.IO.DeltaTime <= 0.0f && g.FrameCount > 0) - g.IO.DeltaTime = 0.00001f; -#endif + if (true) IM_ASSERT(1); else IM_ASSERT(0); // Check user data // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument) @@ -9230,9 +8765,9 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() // One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame(). // It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs. - // We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), + // We silently accommodate for this case by ignoring/ the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), // while still correctly asserting on mid-frame key press events. - const ImGuiKeyChord key_mods = GetMergedModsFromKeys(); + const ImGuiKeyChord key_mods = GetMergedModsFromBools(); IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); IM_UNUSED(key_mods); @@ -9245,9 +8780,7 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() { if (g.CurrentWindowStack.Size > 1) { - ImGuiWindow* window = g.CurrentWindowStack.back().Window; // <-- This window was not Ended! IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); - IM_UNUSED(window); while (g.CurrentWindowStack.Size > 1) End(); } @@ -9344,11 +8877,6 @@ void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, vo if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name); PopStyleVar(); } - while (g.FontStack.Size > stack_sizes->SizeOfFontStack) //-V1044 - { - if (log_callback) log_callback(user_data, "Recovered from missing PopFont() in '%s'", window->Name); - PopFont(); - } while (g.FocusScopeStack.Size > stack_sizes->SizeOfFocusScopeStack + 1) //-V1044 { if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name); @@ -9357,9 +8885,9 @@ void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, vo } // Save current stack sizes for later compare -void ImGuiStackSizes::SetToContextState(ImGuiContext* ctx) +void ImGuiStackSizes::SetToCurrentState() { - ImGuiContext& g = *ctx; + ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; SizeOfIDStack = (short)window->IDStack.Size; SizeOfColorStack = (short)g.ColorStack.Size; @@ -9373,9 +8901,9 @@ void ImGuiStackSizes::SetToContextState(ImGuiContext* ctx) } // Compare to detect usage errors -void ImGuiStackSizes::CompareWithContextState(ImGuiContext* ctx) +void ImGuiStackSizes::CompareWithCurrentState() { - ImGuiContext& g = *ctx; + ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; IM_UNUSED(window); @@ -9451,7 +8979,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x; window->DC.CursorPosPrevLine.y = line_y1; window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); // Next line - window->DC.CursorPos.y = IM_FLOOR(line_y1 + line_height + g.Style.ItemSpacing.y); // Next line + window->DC.CursorPos.y = IM_FLOOR(line_y1 + line_height + g.Style.ItemSpacing.y); // Next line window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] @@ -9480,7 +9008,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu g.LastItemData.ID = id; g.LastItemData.Rect = bb; g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb; - g.LastItemData.InFlags = g.CurrentItemFlags | g.NextItemData.ItemFlags | extra_flags; + g.LastItemData.InFlags = g.CurrentItemFlags | extra_flags; g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None; // Directional navigation processing @@ -9508,15 +9036,14 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu // [DEBUG] People keep stumbling on this problem and using "" as identifier in the root of a window instead of "##something". // Empty identifier are valid and useful in a small amount of cases, but 99.9% of the time you want to use "##something". - // READ THE FAQ: https://dearimgui.com/faq + // READ THE FAQ: https://dearimgui.org/faq IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!"); } g.NextItemData.Flags = ImGuiNextItemDataFlags_None; - g.NextItemData.ItemFlags = ImGuiItemFlags_None; #ifdef IMGUI_ENABLE_TEST_ENGINE if (id != 0) - IMGUI_TEST_ENGINE_ITEM_ADD(id, g.LastItemData.NavRect, &g.LastItemData); + IMGUI_TEST_ENGINE_ITEM_ADD(nav_bb_arg ? *nav_bb_arg : bb, id); #endif // Clipping test @@ -9526,7 +9053,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu // return false; const bool is_rect_visible = bb.Overlaps(window->ClipRect); if (!is_rect_visible) - if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId)) + if (id == 0 || (id != g.ActiveId && id != g.NavId)) if (!g.LogEnabled) return false; @@ -9536,8 +9063,6 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu DebugLocateItemResolveWithLastItem(); #endif //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] - //if ((g.LastItemData.InFlags & ImGuiItemFlags_NoNav) == 0) - // window->DrawList->AddRect(g.LastItemData.NavRect.Min, g.LastItemData.NavRect.Max, IM_COL32(255,255,0,255)); // [DEBUG] // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) if (is_rect_visible) @@ -9778,8 +9303,10 @@ ImVec2 ImGui::GetContentRegionMax() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max; - return mx - window->Pos; + ImVec2 mx = window->ContentRegionRect.Max - window->Pos; + if (window->DC.CurrentColumns || g.CurrentTable) + mx.x = window->WorkRect.Max.x - window->Pos.x; + return mx; } // [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features. @@ -9787,7 +9314,9 @@ ImVec2 ImGui::GetContentRegionMaxAbs() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max; + ImVec2 mx = window->ContentRegionRect.Max; + if (window->DC.CurrentColumns || g.CurrentTable) + mx.x = window->WorkRect.Max.x; return mx; } @@ -9924,24 +9453,38 @@ static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, fl static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) { ImVec2 scroll = window->Scroll; - ImVec2 decoration_size(window->DecoOuterSizeX1 + window->DecoInnerSizeX1 + window->DecoOuterSizeX2, window->DecoOuterSizeY1 + window->DecoInnerSizeY1 + window->DecoOuterSizeY2); - for (int axis = 0; axis < 2; axis++) + if (window->ScrollTarget.x < FLT_MAX) { - if (window->ScrollTarget[axis] < FLT_MAX) + float decoration_total_width = window->ScrollbarSizes.x; + float center_x_ratio = window->ScrollTargetCenterRatio.x; + float scroll_target_x = window->ScrollTarget.x; + if (window->ScrollTargetEdgeSnapDist.x > 0.0f) { - float center_ratio = window->ScrollTargetCenterRatio[axis]; - float scroll_target = window->ScrollTarget[axis]; - if (window->ScrollTargetEdgeSnapDist[axis] > 0.0f) - { - float snap_min = 0.0f; - float snap_max = window->ScrollMax[axis] + window->SizeFull[axis] - decoration_size[axis]; - scroll_target = CalcScrollEdgeSnap(scroll_target, snap_min, snap_max, window->ScrollTargetEdgeSnapDist[axis], center_ratio); - } - scroll[axis] = scroll_target - center_ratio * (window->SizeFull[axis] - decoration_size[axis]); + float snap_x_min = 0.0f; + float snap_x_max = window->ScrollMax.x + window->SizeFull.x - decoration_total_width; + scroll_target_x = CalcScrollEdgeSnap(scroll_target_x, snap_x_min, snap_x_max, window->ScrollTargetEdgeSnapDist.x, center_x_ratio); + } + scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - decoration_total_width); + } + if (window->ScrollTarget.y < FLT_MAX) + { + float decoration_total_height = window->TitleBarHeight() + window->MenuBarHeight() + window->ScrollbarSizes.y; + float center_y_ratio = window->ScrollTargetCenterRatio.y; + float scroll_target_y = window->ScrollTarget.y; + if (window->ScrollTargetEdgeSnapDist.y > 0.0f) + { + float snap_y_min = 0.0f; + float snap_y_max = window->ScrollMax.y + window->SizeFull.y - decoration_total_height; + scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio); } - scroll[axis] = IM_FLOOR(ImMax(scroll[axis], 0.0f)); - if (!window->Collapsed && !window->SkipItems) - scroll[axis] = ImMin(scroll[axis], window->ScrollMax[axis]); + scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - decoration_total_height); + } + scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f)); + scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f)); + if (!window->Collapsed && !window->SkipItems) + { + scroll.x = ImMin(scroll.x, window->ScrollMax.x); + scroll.y = ImMin(scroll.y, window->ScrollMax.y); } return scroll; } @@ -9962,11 +9505,8 @@ void ImGui::ScrollToRect(ImGuiWindow* window, const ImRect& item_rect, ImGuiScro ImVec2 ImGui::ScrollToRectEx(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags) { ImGuiContext& g = *GImGui; - ImRect scroll_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)); - scroll_rect.Min.x = ImMin(scroll_rect.Min.x + window->DecoInnerSizeX1, scroll_rect.Max.x); - scroll_rect.Min.y = ImMin(scroll_rect.Min.y + window->DecoInnerSizeY1, scroll_rect.Max.y); - //GetForegroundDrawList(window)->AddRect(item_rect.Min, item_rect.Max, IM_COL32(255,0,0,255), 0.0f, 0, 5.0f); // [DEBUG] - //GetForegroundDrawList(window)->AddRect(scroll_rect.Min, scroll_rect.Max, IM_COL32_WHITE); // [DEBUG] + ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)); + //GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG] // Check that only one behavior is selected per axis IM_ASSERT((flags & ImGuiScrollFlags_MaskX_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskX_)); @@ -9979,39 +9519,35 @@ ImVec2 ImGui::ScrollToRectEx(ImGuiWindow* window, const ImRect& item_rect, ImGui if ((flags & ImGuiScrollFlags_MaskY_) == 0) flags |= window->Appearing ? ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeY; - const bool fully_visible_x = item_rect.Min.x >= scroll_rect.Min.x && item_rect.Max.x <= scroll_rect.Max.x; - const bool fully_visible_y = item_rect.Min.y >= scroll_rect.Min.y && item_rect.Max.y <= scroll_rect.Max.y; - const bool can_be_fully_visible_x = (item_rect.GetWidth() + g.Style.ItemSpacing.x * 2.0f) <= scroll_rect.GetWidth() || (window->AutoFitFramesX > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0; - const bool can_be_fully_visible_y = (item_rect.GetHeight() + g.Style.ItemSpacing.y * 2.0f) <= scroll_rect.GetHeight() || (window->AutoFitFramesY > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0; + const bool fully_visible_x = item_rect.Min.x >= window_rect.Min.x && item_rect.Max.x <= window_rect.Max.x; + const bool fully_visible_y = item_rect.Min.y >= window_rect.Min.y && item_rect.Max.y <= window_rect.Max.y; + const bool can_be_fully_visible_x = (item_rect.GetWidth() + g.Style.ItemSpacing.x * 2.0f) <= window_rect.GetWidth(); + const bool can_be_fully_visible_y = (item_rect.GetHeight() + g.Style.ItemSpacing.y * 2.0f) <= window_rect.GetHeight(); if ((flags & ImGuiScrollFlags_KeepVisibleEdgeX) && !fully_visible_x) { - if (item_rect.Min.x < scroll_rect.Min.x || !can_be_fully_visible_x) + if (item_rect.Min.x < window_rect.Min.x || !can_be_fully_visible_x) SetScrollFromPosX(window, item_rect.Min.x - g.Style.ItemSpacing.x - window->Pos.x, 0.0f); - else if (item_rect.Max.x >= scroll_rect.Max.x) + else if (item_rect.Max.x >= window_rect.Max.x) SetScrollFromPosX(window, item_rect.Max.x + g.Style.ItemSpacing.x - window->Pos.x, 1.0f); } else if (((flags & ImGuiScrollFlags_KeepVisibleCenterX) && !fully_visible_x) || (flags & ImGuiScrollFlags_AlwaysCenterX)) { - if (can_be_fully_visible_x) - SetScrollFromPosX(window, ImFloor((item_rect.Min.x + item_rect.Max.x) * 0.5f) - window->Pos.x, 0.5f); - else - SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x, 0.0f); + float target_x = can_be_fully_visible_x ? ImFloor((item_rect.Min.x + item_rect.Max.x - window->InnerRect.GetWidth()) * 0.5f) : item_rect.Min.x; + SetScrollFromPosX(window, target_x - window->Pos.x, 0.0f); } if ((flags & ImGuiScrollFlags_KeepVisibleEdgeY) && !fully_visible_y) { - if (item_rect.Min.y < scroll_rect.Min.y || !can_be_fully_visible_y) + if (item_rect.Min.y < window_rect.Min.y || !can_be_fully_visible_y) SetScrollFromPosY(window, item_rect.Min.y - g.Style.ItemSpacing.y - window->Pos.y, 0.0f); - else if (item_rect.Max.y >= scroll_rect.Max.y) + else if (item_rect.Max.y >= window_rect.Max.y) SetScrollFromPosY(window, item_rect.Max.y + g.Style.ItemSpacing.y - window->Pos.y, 1.0f); } else if (((flags & ImGuiScrollFlags_KeepVisibleCenterY) && !fully_visible_y) || (flags & ImGuiScrollFlags_AlwaysCenterY)) { - if (can_be_fully_visible_y) - SetScrollFromPosY(window, ImFloor((item_rect.Min.y + item_rect.Max.y) * 0.5f) - window->Pos.y, 0.5f); - else - SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y, 0.0f); + float target_y = can_be_fully_visible_y ? ImFloor((item_rect.Min.y + item_rect.Max.y - window->InnerRect.GetHeight()) * 0.5f) : item_rect.Min.y; + SetScrollFromPosY(window, target_y - window->Pos.y, 0.0f); } ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); @@ -10094,7 +9630,7 @@ void ImGui::SetScrollY(float scroll_y) void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio) { IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f); - window->ScrollTarget.x = IM_FLOOR(local_x - window->DecoOuterSizeX1 - window->DecoInnerSizeX1 + window->Scroll.x); // Convert local position to scroll offset + window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x); // Convert local position to scroll offset window->ScrollTargetCenterRatio.x = center_x_ratio; window->ScrollTargetEdgeSnapDist.x = 0.0f; } @@ -10102,7 +9638,9 @@ void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio) { IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); - window->ScrollTarget.y = IM_FLOOR(local_y - window->DecoOuterSizeY1 - window->DecoInnerSizeY1 + window->Scroll.y); // Convert local position to scroll offset + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect; + local_y -= decoration_up_height; + window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); // Convert local position to scroll offset window->ScrollTargetCenterRatio.y = center_y_ratio; window->ScrollTargetEdgeSnapDist.y = 0.0f; } @@ -10149,55 +9687,41 @@ void ImGui::SetScrollHereY(float center_y_ratio) // [SECTION] TOOLTIPS //----------------------------------------------------------------------------- -bool ImGui::BeginTooltip() -{ - return BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None); -} - -bool ImGui::BeginItemTooltip() +void ImGui::BeginTooltip() { - if (!IsItemHovered(ImGuiHoveredFlags_ForTooltip)) - return false; - return BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None); + BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None); } -bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags) +void ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags) { ImGuiContext& g = *GImGui; if (g.DragDropWithinSource || g.DragDropWithinTarget) { - // Drag and Drop tooltips are positioning differently than other tooltips: - // - offset visibility to increase visibility around mouse. - // - never clamp within outer viewport boundary. - // We call SetNextWindowPos() to enforce position and disable clamping. - // See FindBestWindowPosForPopup() for positionning logic of other tooltips (not drag and drop ones). + // The default tooltip position is a little offset to give space to see the context menu (it's also clamped within the current viewport/monitor) + // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor. + // Whatever we do we want to call SetNextWindowPos() to enforce a tooltip position and disable clipping the tooltip without our display area, like regular tooltip do. //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; - ImVec2 tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET * g.Style.MouseCursorScale; + ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale); SetNextWindowPos(tooltip_pos); SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :( - tooltip_flags |= ImGuiTooltipFlags_OverridePrevious; + tooltip_flags |= ImGuiTooltipFlags_OverridePreviousTooltip; } char window_name[16]; ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); - if (tooltip_flags & ImGuiTooltipFlags_OverridePrevious) + if (tooltip_flags & ImGuiTooltipFlags_OverridePreviousTooltip) if (ImGuiWindow* window = FindWindowByName(window_name)) if (window->Active) { // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. - SetWindowHiddendAndSkipItemsForCurrentFrame(window); + window->Hidden = true; + window->HiddenFramesCanSkipItems = 1; // FIXME: This may not be necessary? ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); } ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize; Begin(window_name, NULL, flags | extra_window_flags); - // 2023-03-09: Added bool return value to the API, but currently always returning true. - // If this ever returns false we need to update BeginDragDropSource() accordingly. - //if (!ret) - // End(); - //return ret; - return true; } void ImGui::EndTooltip() @@ -10206,40 +9730,21 @@ void ImGui::EndTooltip() End(); } -void ImGui::SetTooltip(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - SetTooltipV(fmt, args); - va_end(args); -} - void ImGui::SetTooltipV(const char* fmt, va_list args) { - if (!BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None)) - return; + BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None); TextV(fmt, args); EndTooltip(); } -// Shortcut to use 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav'. -// Defaults to == ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort when using the mouse. -void ImGui::SetItemTooltip(const char* fmt, ...) +void ImGui::SetTooltip(const char* fmt, ...) { va_list args; va_start(args, fmt); - if (IsItemHovered(ImGuiHoveredFlags_ForTooltip)) - SetTooltipV(fmt, args); + SetTooltipV(fmt, args); va_end(args); } -void ImGui::SetItemTooltipV(const char* fmt, va_list args) -{ - if (IsItemHovered(ImGuiHoveredFlags_ForTooltip)) - SetTooltipV(fmt, args); -} - - //----------------------------------------------------------------------------- // [SECTION] POPUPS //----------------------------------------------------------------------------- @@ -10285,7 +9790,6 @@ bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags) return IsPopupOpen(id, popup_flags); } -// Also see FindBlockingModal(NULL) ImGuiWindow* ImGui::GetTopMostPopupModal() { ImGuiContext& g = *GImGui; @@ -10296,7 +9800,6 @@ ImGuiWindow* ImGui::GetTopMostPopupModal() return NULL; } -// See Demo->Stacked Modal to confirm what this is for. ImGuiWindow* ImGui::GetTopMostAndVisiblePopupModal() { ImGuiContext& g = *GImGui; @@ -10311,7 +9814,7 @@ void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags) { ImGuiContext& g = *GImGui; ImGuiID id = g.CurrentWindow->GetID(str_id); - IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopup(\"%s\" -> 0x%08X)\n", str_id, id); + IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopup(\"%s\" -> 0x%08X\n", str_id, id); OpenPopupEx(id, popup_flags); } @@ -10331,7 +9834,7 @@ void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags) const int current_stack_size = g.BeginPopupStack.Size; if (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup) - if (IsPopupOpen((ImGuiID)0, ImGuiPopupFlags_AnyPopupId)) + if (IsPopupOpen(0u, ImGuiPopupFlags_AnyPopupId)) return; ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. @@ -10425,7 +9928,7 @@ void ImGui::ClosePopupsExceptModals() for (popup_count_to_keep = g.OpenPopupStack.Size; popup_count_to_keep > 0; popup_count_to_keep--) { ImGuiWindow* window = g.OpenPopupStack[popup_count_to_keep - 1].Window; - if (!window || (window->Flags & ImGuiWindowFlags_Modal)) + if (!window || window->Flags & ImGuiWindowFlags_Modal) break; } if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below @@ -10447,9 +9950,16 @@ void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_ { ImGuiWindow* focus_window = (popup_window && popup_window->Flags & ImGuiWindowFlags_ChildMenu) ? popup_window->ParentWindow : popup_backup_nav_window; if (focus_window && !focus_window->WasActive && popup_window) - FocusTopMostWindowUnderOne(popup_window, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild); // Fallback + { + // Fallback + FocusTopMostWindowUnderOne(popup_window, NULL); + } else - FocusWindow(focus_window, (g.NavLayer == ImGuiNavLayer_Main) ? ImGuiFocusRequestFlags_RestoreFocusedChild : ImGuiFocusRequestFlags_None); + { + if (g.NavLayer == ImGuiNavLayer_Main && focus_window) + focus_window = NavRestoreLastChildNavWindow(focus_window); + FocusWindow(focus_window); + } } } @@ -10762,20 +10272,15 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) } if (window->Flags & ImGuiWindowFlags_Tooltip) { - // Position tooltip (always follows mouse + clamp within outer boundaries) - // Note that drag and drop tooltips are NOT using this path: BeginTooltipEx() manually sets their position. - // In theory we could handle both cases in same location, but requires a bit of shuffling as drag and drop tooltips are calling SetWindowPos() leading to 'window_pos_set_by_api' being set in Begin() - IM_ASSERT(g.CurrentWindow == window); - const float scale = g.Style.MouseCursorScale; - const ImVec2 ref_pos = NavCalcPreferredRefPos(); - const ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET * scale; + // Position tooltip (always follows mouse) + float sc = g.Style.MouseCursorScale; + ImVec2 ref_pos = NavCalcPreferredRefPos(); ImRect r_avoid; if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); else - r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * scale, ref_pos.y + 24 * scale); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. - //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255, 0, 255, 255)); - return FindBestWindowPosForPopupEx(tooltip_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip); + r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. + return FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip); } IM_ASSERT(0); return window->Pos; @@ -10801,12 +10306,6 @@ void ImGui::SetNavWindow(ImGuiWindow* window) NavUpdateAnyRequestFlag(); } -void ImGui::NavClearPreferredPosForAxis(ImGuiAxis axis) -{ - ImGuiContext& g = *GImGui; - g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer][axis] = FLT_MAX; -} - void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel) { ImGuiContext& g = *GImGui; @@ -10817,10 +10316,6 @@ void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id g.NavFocusScopeId = focus_scope_id; g.NavWindow->NavLastIds[nav_layer] = id; g.NavWindow->NavRectRel[nav_layer] = rect_rel; - - // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it) - NavClearPreferredPosForAxis(ImGuiAxis_X); - NavClearPreferredPosForAxis(ImGuiAxis_Y); } void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) @@ -10841,32 +10336,42 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) if (g.LastItemData.ID == id) window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect); - if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) + if (g.ActiveIdSource == ImGuiInputSource_Nav) g.NavDisableMouseHover = true; else g.NavDisableHighlight = true; - - // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it) - NavClearPreferredPosForAxis(ImGuiAxis_X); - NavClearPreferredPosForAxis(ImGuiAxis_Y); } -static ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) +ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) { if (ImFabs(dx) > ImFabs(dy)) return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left; return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; } -static float inline NavScoreItemDistInterval(float cand_min, float cand_max, float curr_min, float curr_max) +static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1) { - if (cand_max < curr_min) - return cand_max - curr_min; - if (curr_max < cand_min) - return cand_min - curr_max; + if (a1 < b0) + return a1 - b0; + if (b1 < a0) + return a0 - b1; return 0.0f; } +static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect) +{ + if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) + { + r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y); + r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y); + } + else // FIXME: PageUp/PageDown are leaving move_dir == None + { + r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x); + r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x); + } +} + // Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057 static bool ImGui::NavScoreItem(ImGuiNavItemData* result) { @@ -10889,6 +10394,10 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result) cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window } + // We perform scoring on items bounding box clipped by the current clipping rectangle on the other axis (clipping on our movement axis would give us equal scores for all clipped items) + // For example, this ensures that items in one column are not reached when moving vertically from items in another column. + NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect); + // Compute distance between boxes // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x); @@ -10927,41 +10436,32 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result) quadrant = (g.LastItemData.ID < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; } - const ImGuiDir move_dir = g.NavMoveDir; #if IMGUI_DEBUG_NAV_SCORING - char buf[200]; - if (g.IO.KeyCtrl) // Hold CTRL to preview score in matching quadrant. CTRL+Arrow to rotate. + char buf[128]; + if (IsMouseHoveringRect(cand.Min, cand.Max)) { - if (quadrant == move_dir) - { - ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); - ImDrawList* draw_list = GetForegroundDrawList(window); - draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 80)); - draw_list->AddRectFilled(cand.Min, cand.Min + CalcTextSize(buf), IM_COL32(255, 0, 0, 200)); - draw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf); - } + ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]); + ImDrawList* draw_list = GetForegroundDrawList(window); + draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100)); + draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200)); + draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40,0,0,150)); + draw_list->AddText(cand.Max, ~0U, buf); } - const bool debug_hovering = IsMouseHoveringRect(cand.Min, cand.Max); - const bool debug_tty = (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_Space)); - if (debug_hovering || debug_tty) + else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate. { - ImFormatString(buf, IM_ARRAYSIZE(buf), - "d-box (%7.3f,%7.3f) -> %7.3f\nd-center (%7.3f,%7.3f) -> %7.3f\nd-axial (%7.3f,%7.3f) -> %7.3f\nnav %c, quadrant %c", - dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "-WENS"[move_dir+1], "-WENS"[quadrant+1]); - if (debug_hovering) + if (quadrant == g.NavMoveDir) { + ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); ImDrawList* draw_list = GetForegroundDrawList(window); - draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255, 200, 0, 100)); - draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255, 255, 0, 200)); - draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40, 0, 0, 200)); - draw_list->AddText(cand.Max, ~0U, buf); + draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200)); + draw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf); } - if (debug_tty) { IMGUI_DEBUG_LOG_NAV("id 0x%08X\n%s\n", g.LastItemData.ID, buf); } } #endif // Is it in the quadrant we're interested in moving to? bool new_best = false; + const ImGuiDir move_dir = g.NavMoveDir; if (quadrant == move_dir) { // Does it beat the current best candidate? @@ -11017,15 +10517,6 @@ static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result) result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect); } -// True when current work location may be scrolled horizontally when moving left / right. -// This is generally always true UNLESS within a column. We don't have a vertical equivalent. -void ImGui::NavUpdateCurrentWindowIsScrollPushableX() -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - window->DC.NavIsScrollPushableX = (g.CurrentTable == NULL && window->DC.CurrentColumns == NULL); -} - // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) // This is called after LastItemData is set. static void ImGui::NavProcessItem() @@ -11033,24 +10524,18 @@ static void ImGui::NavProcessItem() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; const ImGuiID id = g.LastItemData.ID; - const ImGuiItemFlags item_flags = g.LastItemData.InFlags; - - // When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221) - if (window->DC.NavIsScrollPushableX == false) - { - g.LastItemData.NavRect.Min.x = ImClamp(g.LastItemData.NavRect.Min.x, window->ClipRect.Min.x, window->ClipRect.Max.x); - g.LastItemData.NavRect.Max.x = ImClamp(g.LastItemData.NavRect.Max.x, window->ClipRect.Min.x, window->ClipRect.Max.x); - } const ImRect nav_bb = g.LastItemData.NavRect; + const ImGuiItemFlags item_flags = g.LastItemData.InFlags; // Process Init Request if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent && (item_flags & ImGuiItemFlags_Disabled) == 0) { // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback const bool candidate_for_nav_default_focus = (item_flags & ImGuiItemFlags_NoNavDefaultFocus) == 0; - if (candidate_for_nav_default_focus || g.NavInitResult.ID == 0) + if (candidate_for_nav_default_focus || g.NavInitResultId == 0) { - NavApplyItemToResult(&g.NavInitResult); + g.NavInitResultId = id; + g.NavInitResultRectRel = WindowRectAbsToRel(window, nav_bb); } if (candidate_for_nav_default_focus) { @@ -11061,29 +10546,34 @@ static void ImGui::NavProcessItem() // Process Move Request (scoring for navigation) // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRect + scoring from a rect wrapped according to current wrapping policy) - if (g.NavMoveScoringItems && (item_flags & ImGuiItemFlags_Disabled) == 0) + if (g.NavMoveScoringItems) { - const bool is_tabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) != 0; + const bool is_tab_stop = (item_flags & ImGuiItemFlags_Inputable) && (item_flags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0; + const bool is_tabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) != 0; if (is_tabbing) { - NavProcessItemForTabbingRequest(id, item_flags, g.NavMoveFlags); + if (is_tab_stop || (g.NavMoveFlags & ImGuiNavMoveFlags_FocusApi)) + NavProcessItemForTabbingRequest(id); } - else if (g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) + else if ((g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & ImGuiItemFlags_Disabled)) { ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; - if (NavScoreItem(result)) - NavApplyItemToResult(result); - - // Features like PageUp/PageDown need to maintain a separate score for the visible set of items. - const float VISIBLE_RATIO = 0.70f; - if ((g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) - if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) - if (NavScoreItem(&g.NavMoveResultLocalVisible)) - NavApplyItemToResult(&g.NavMoveResultLocalVisible); + if (!is_tabbing) + { + if (NavScoreItem(result)) + NavApplyItemToResult(result); + + // Features like PageUp/PageDown need to maintain a separate score for the visible set of items. + const float VISIBLE_RATIO = 0.70f; + if ((g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) + if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) + if (NavScoreItem(&g.NavMoveResultLocalVisible)) + NavApplyItemToResult(&g.NavMoveResultLocalVisible); + } } } - // Update information for currently focused/navigated item + // Update window-relative bounding box of navigated item if (g.NavId == id) { if (g.NavWindow != window) @@ -11091,7 +10581,7 @@ static void ImGui::NavProcessItem() g.NavLayer = window->DC.NavLayerCurrent; g.NavFocusScopeId = g.CurrentFocusScopeId; g.NavIdIsAlive = true; - window->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position) + window->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position) } } @@ -11102,31 +10592,18 @@ static void ImGui::NavProcessItem() // - Case 3: tab forward wrap: set result to first eligible item (preemptively), on ref id set counter, on next frame if counter hasn't elapsed store result. // FIXME-TABBING: Could be done as a next-frame forwarded request // - Case 4: tab backward: store all results, on ref id pick prev, stop storing // - Case 5: tab backward wrap: store all results, on ref id if no result keep storing until last // FIXME-TABBING: Could be done as next-frame forwarded requested -void ImGui::NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags) +void ImGui::NavProcessItemForTabbingRequest(ImGuiID id) { ImGuiContext& g = *GImGui; - if ((move_flags & ImGuiNavMoveFlags_FocusApi) == 0) - if (g.NavLayer != g.CurrentWindow->DC.NavLayerCurrent) - return; - - // - Can always land on an item when using API call. - // - Tabbing with _NavEnableKeyboard (space/enter/arrows): goes through every item. - // - Tabbing without _NavEnableKeyboard: goes through inputable items only. - bool can_stop; - if (move_flags & ImGuiNavMoveFlags_FocusApi) - can_stop = true; - else - can_stop = (item_flags & ImGuiItemFlags_NoTabStop) == 0 && ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) || (item_flags & ImGuiItemFlags_Inputable)); - // Always store in NavMoveResultLocal (unlike directional request which uses NavMoveResultOther on sibling/flattened windows) ImGuiNavItemData* result = &g.NavMoveResultLocal; if (g.NavTabbingDir == +1) { // Tab Forward or SetKeyboardFocusHere() with >= 0 - if (can_stop && g.NavTabbingResultFirst.ID == 0) + if (g.NavTabbingResultFirst.ID == 0) NavApplyItemToResult(&g.NavTabbingResultFirst); - if (can_stop && g.NavTabbingCounter > 0 && --g.NavTabbingCounter == 0) + if (--g.NavTabbingCounter == 0) NavMoveRequestResolveWithLastItem(result); else if (g.NavId == id) g.NavTabbingCounter = 1; @@ -11142,18 +10619,16 @@ void ImGui::NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flag NavUpdateAnyRequestFlag(); } } - else if (can_stop) + else { - // Keep applying until reaching NavId NavApplyItemToResult(result); } } else if (g.NavTabbingDir == 0) { - if (can_stop && g.NavId == id) - NavMoveRequestResolveWithLastItem(result); - if (can_stop && g.NavTabbingResultFirst.ID == 0) // Tab init - NavApplyItemToResult(&g.NavTabbingResultFirst); + // Tab Init + if (g.NavTabbingResultFirst.ID == 0) + NavMoveRequestResolveWithLastItem(&g.NavTabbingResultFirst); } } @@ -11169,7 +10644,7 @@ void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavM ImGuiContext& g = *GImGui; IM_ASSERT(g.NavWindow != NULL); - if (move_flags & ImGuiNavMoveFlags_IsTabbing) + if (move_flags & ImGuiNavMoveFlags_Tabbing) move_flags |= ImGuiNavMoveFlags_AllowCurrentNavId; g.NavMoveSubmitted = g.NavMoveScoringItems = true; @@ -11221,12 +10696,10 @@ void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNav void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags wrap_flags) { ImGuiContext& g = *GImGui; - IM_ASSERT((wrap_flags & ImGuiNavMoveFlags_WrapMask_ ) != 0 && (wrap_flags & ~ImGuiNavMoveFlags_WrapMask_) == 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY - - // In theory we should test for NavMoveRequestButNoResultYet() but there's no point doing it: - // as NavEndFrame() will do the same test. It will end up calling NavUpdateCreateWrappingRequest(). + IM_ASSERT(wrap_flags != 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY + // In theory we should test for NavMoveRequestButNoResultYet() but there's no point doing it, NavEndFrame() will do the same test if (g.NavWindow == window && g.NavMoveScoringItems && g.NavLayer == ImGuiNavLayer_Main) - g.NavMoveFlags = (g.NavMoveFlags & ~ImGuiNavMoveFlags_WrapMask_) | wrap_flags; + g.NavMoveFlags |= wrap_flags; } // FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0). @@ -11308,7 +10781,8 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) SetNavID(0, g.NavLayer, window->NavRootFocusScopeId, ImRect()); g.NavInitRequest = true; g.NavInitRequestFromMove = false; - g.NavInitResult.ID = 0; + g.NavInitResultId = 0; + g.NavInitResultRectRel = ImRect(); NavUpdateAnyRequestFlag(); } else @@ -11393,12 +10867,12 @@ static void ImGui::NavUpdate() g.NavInputSource = ImGuiInputSource_Keyboard; // Process navigation init request (select first/default focus) - g.NavJustMovedToId = 0; - if (g.NavInitResult.ID != 0) + if (g.NavInitResultId != 0) NavInitRequestApplyResult(); g.NavInitRequest = false; g.NavInitRequestFromMove = false; - g.NavInitResult.ID = 0; + g.NavInitResultId = 0; + g.NavJustMovedToId = 0; // Process navigation move request if (g.NavMoveSubmitted) @@ -11431,7 +10905,7 @@ static void ImGui::NavUpdate() NavUpdateCancelRequest(); // Process manual activation request - g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = 0; + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavActivateInputId = 0; g.NavActivateFlags = ImGuiActivateFlags_None; if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) { @@ -11446,12 +10920,12 @@ static void ImGui::NavUpdate() } if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && input_pressed) { - g.NavActivateId = g.NavId; + g.NavActivateInputId = g.NavId; g.NavActivateFlags = ImGuiActivateFlags_PreferInput; } - if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_down || input_down)) + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) g.NavActivateDownId = g.NavId; - if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_pressed || input_pressed)) + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) g.NavActivatePressedId = g.NavId; } if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) @@ -11463,7 +10937,10 @@ static void ImGui::NavUpdate() // FIXME-NAV: Those should eventually be queued (unlike focus they don't cancel each others) if (g.NavNextActivateId != 0) { - g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavNextActivateId; + if (g.NavNextActivateFlags & ImGuiActivateFlags_PreferInput) + g.NavActivateInputId = g.NavNextActivateId; + else + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavNextActivateId; g.NavActivateFlags = g.NavNextActivateFlags; } g.NavNextActivateId = 0; @@ -11482,7 +10959,7 @@ static void ImGui::NavUpdate() ImGuiWindow* window = g.NavWindow; const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. const ImGuiDir move_dir = g.NavMoveDir; - if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY && move_dir != ImGuiDir_None) + if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && move_dir != ImGuiDir_None) { if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) SetScrollX(window, ImFloor(window->Scroll.x + ((move_dir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); @@ -11494,7 +10971,7 @@ static void ImGui::NavUpdate() // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds. if (nav_gamepad_active) { - const ImVec2 scroll_dir = GetKeyMagnitude2d(ImGuiKey_GamepadLStickLeft, ImGuiKey_GamepadLStickRight, ImGuiKey_GamepadLStickUp, ImGuiKey_GamepadLStickDown); + const ImVec2 scroll_dir = GetKeyVector2d(ImGuiKey_GamepadLStickLeft, ImGuiKey_GamepadLStickRight, ImGuiKey_GamepadLStickUp, ImGuiKey_GamepadLStickDown); const float tweak_factor = IsKeyDown(ImGuiKey_NavGamepadTweakSlow) ? 1.0f / 10.0f : IsKeyDown(ImGuiKey_NavGamepadTweakFast) ? 10.0f : 1.0f; if (scroll_dir.x != 0.0f && window->ScrollbarX) SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed * tweak_factor)); @@ -11522,11 +10999,11 @@ static void ImGui::NavUpdate() // [DEBUG] g.NavScoringDebugCount = 0; #if IMGUI_DEBUG_NAV_RECTS - if (ImGuiWindow* debug_window = g.NavWindow) + if (g.NavWindow) { - ImDrawList* draw_list = GetForegroundDrawList(debug_window); - int layer = g.NavLayer; /* for (int layer = 0; layer < 2; layer++)*/ { ImRect r = WindowRectRelToAbs(debug_window, debug_window->NavRectRel[layer]); draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 200, 0, 255)); } - //if (1) { ImU32 col = (!debug_window->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); } + ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow); + if (1) { for (int layer = 0; layer < 2; layer++) { ImRect r = WindowRectRelToAbs(g.NavWindow, g.NavWindow->NavRectRel[layer]); draw_list->AddRect(r.Min, r.Max, IM_COL32(255,200,0,255)); } } // [DEBUG] + if (1) { ImU32 col = (!g.NavWindow->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); } } #endif } @@ -11538,48 +11015,15 @@ void ImGui::NavInitRequestApplyResult() if (!g.NavWindow) return; - ImGuiNavItemData* result = &g.NavInitResult; - if (g.NavId != result->ID) - { - g.NavJustMovedToId = result->ID; - g.NavJustMovedToFocusScopeId = result->FocusScopeId; - g.NavJustMovedToKeyMods = 0; - } - // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) // FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently. - IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: ApplyResult: NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); - SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: ApplyResult: NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name); + SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel); g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result if (g.NavInitRequestFromMove) NavRestoreHighlightAfterMove(); } -// Bias scoring rect ahead of scoring + update preferred pos (if missing) using source position -static void NavBiasScoringRect(ImRect& r, ImVec2& preferred_pos_rel, ImGuiDir move_dir, ImGuiNavMoveFlags move_flags) -{ - // Bias initial rect - ImGuiContext& g = *GImGui; - const ImVec2 rel_to_abs_offset = g.NavWindow->DC.CursorStartPos; - - // Initialize bias on departure if we don't have any. So mouse-click + arrow will record bias. - // - We default to L/U bias, so moving down from a large source item into several columns will land on left-most column. - // - But each successful move sets new bias on one axis, only cleared when using mouse. - if ((move_flags & ImGuiNavMoveFlags_Forwarded) == 0) - { - if (preferred_pos_rel.x == FLT_MAX) - preferred_pos_rel.x = ImMin(r.Min.x + 1.0f, r.Max.x) - rel_to_abs_offset.x; - if (preferred_pos_rel.y == FLT_MAX) - preferred_pos_rel.y = r.GetCenter().y - rel_to_abs_offset.y; - } - - // Apply general bias on the other axis - if ((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) && preferred_pos_rel.x != FLT_MAX) - r.Min.x = r.Max.x = preferred_pos_rel.x + rel_to_abs_offset.x; - else if ((move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) && preferred_pos_rel.y != FLT_MAX) - r.Min.y = r.Max.y = preferred_pos_rel.y + rel_to_abs_offset.y; -} - void ImGui::NavUpdateCreateMoveRequest() { ImGuiContext& g = *GImGui; @@ -11604,7 +11048,7 @@ void ImGui::NavUpdateCreateMoveRequest() g.NavMoveScrollFlags = ImGuiScrollFlags_None; if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs)) { - const ImGuiInputFlags repeat_mode = ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateNavMove; + const ImGuiInputFlags repeat_mode = ImGuiInputFlags_Repeat | ImGuiInputFlags_RepeatRateNavMove; if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadLeft, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_LeftArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Left; } if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadRight, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_RightArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Right; } if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadUp, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_UpArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Up; } @@ -11625,15 +11069,13 @@ void ImGui::NavUpdateCreateMoveRequest() g.NavScoringNoClipRect.TranslateY(scoring_rect_offset_y); } - // [DEBUG] Always send a request when holding CTRL. Hold CTRL + Arrow change the direction. + // [DEBUG] Always send a request #if IMGUI_DEBUG_NAV_SCORING - //if (io.KeyCtrl && IsKeyPressed(ImGuiKey_C)) - // g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3); - if (io.KeyCtrl) + if (io.KeyCtrl && IsKeyPressed(ImGuiKey_C)) + g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3); + if (io.KeyCtrl && g.NavMoveDir == ImGuiDir_None) { - if (g.NavMoveDir == ImGuiDir_None) - g.NavMoveDir = g.NavMoveDirForDebug; - g.NavMoveClipDir = g.NavMoveDir; + g.NavMoveDir = g.NavMoveDirForDebug; g.NavMoveFlags |= ImGuiNavMoveFlags_DebugNoResult; } #endif @@ -11648,26 +11090,21 @@ void ImGui::NavUpdateCreateMoveRequest() { IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "", g.NavLayer); g.NavInitRequest = g.NavInitRequestFromMove = true; - g.NavInitResult.ID = 0; + g.NavInitResultId = 0; g.NavDisableHighlight = false; } // When using gamepad, we project the reference nav bounding box into window visible area. - // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, - // since with gamepad all movements are relative (can't focus a visible object like we can with the mouse). + // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad all movements are relative + // (can't focus a visible object like we can with the mouse). if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded)) { bool clamp_x = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapX)) == 0; bool clamp_y = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapY)) == 0; ImRect inner_rect_rel = WindowRectAbsToRel(window, ImRect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1))); - - // Take account of changing scroll to handle triggering a new move request on a scrolling frame. (#6171) - // Otherwise 'inner_rect_rel' would be off on the move result frame. - inner_rect_rel.Translate(CalcNextScrollFromScrollTargetAndClamp(window) - window->Scroll); - if ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[g.NavLayer])) { - IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n"); + //IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n"); float pad_x = ImMin(inner_rect_rel.GetWidth(), window->CalcFontSize() * 0.5f); float pad_y = ImMin(inner_rect_rel.GetHeight(), window->CalcFontSize() * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item inner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -FLT_MAX; @@ -11686,8 +11123,8 @@ void ImGui::NavUpdateCreateMoveRequest() ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); scoring_rect = WindowRectRelToAbs(window, nav_rect_rel); scoring_rect.TranslateY(scoring_rect_offset_y); - if (g.NavMoveSubmitted) - NavBiasScoringRect(scoring_rect, window->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer], g.NavMoveDir, g.NavMoveFlags); + scoring_rect.Min.x = ImMin(scoring_rect.Min.x + 1.0f, scoring_rect.Max.x); + scoring_rect.Max.x = scoring_rect.Min.x; IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem(). //GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG] //if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG] @@ -11712,15 +11149,11 @@ void ImGui::NavUpdateCreateTabbingRequest() // (this is ALWAYS ENABLED, regardless of ImGuiConfigFlags_NavEnableKeyboard flag!) // Initially this was designed to use counters and modulo arithmetic, but that could not work with unsubmitted items (list clipper). Instead we use a strategy close to other move requests. // See NavProcessItemForTabbingRequest() for a description of the various forward/backward tabbing cases with and without wrapping. - const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; - if (nav_keyboard_active) - g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.NavDisableHighlight == true && g.ActiveId == 0) ? 0 : +1; - else - g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1; - ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate; + //// FIXME: We use (g.ActiveId == 0) but (g.NavDisableHighlight == false) might be righter once we can tab through anything + g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1; ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; ImGuiDir clip_dir = (g.NavTabbingDir < 0) ? ImGuiDir_Up : ImGuiDir_Down; - NavMoveRequestSubmit(ImGuiDir_None, clip_dir, move_flags, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. + NavMoveRequestSubmit(ImGuiDir_None, clip_dir, ImGuiNavMoveFlags_Tabbing, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. g.NavTabbingCounter = -1; } @@ -11737,20 +11170,17 @@ void ImGui::NavMoveRequestApplyResult() ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : (g.NavMoveResultOther.ID != 0) ? &g.NavMoveResultOther : NULL; // Tabbing forward wrap - if ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && result == NULL) + if (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) if ((g.NavTabbingCounter == 1 || g.NavTabbingDir == 0) && g.NavTabbingResultFirst.ID) result = &g.NavTabbingResultFirst; // In a situation when there are no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) - const ImGuiAxis axis = (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; if (result == NULL) { - if (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) - g.NavMoveFlags |= ImGuiNavMoveFlags_NoSetNavHighlight; - if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavHighlight) == 0) + if (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) + g.NavMoveFlags |= ImGuiNavMoveFlags_DontSetNavHighlight; + if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0) NavRestoreHighlightAfterMove(); - NavClearPreferredPosForAxis(axis); // On a failed move, clear preferred pos for this axis. - IMGUI_DEBUG_LOG_NAV("[nav] NavMoveSubmitted but not led to a result!\n"); return; } @@ -11768,15 +11198,17 @@ void ImGui::NavMoveRequestApplyResult() // Scroll to keep newly navigated item fully into view. if (g.NavLayer == ImGuiNavLayer_Main) { - ImRect rect_abs = WindowRectRelToAbs(result->Window, result->RectRel); - ScrollToRectEx(result->Window, rect_abs, g.NavMoveScrollFlags); - if (g.NavMoveFlags & ImGuiNavMoveFlags_ScrollToEdgeY) { - // FIXME: Should remove this? Or make more precise: use ScrollToRectEx() with edge? + // FIXME: Should remove this float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f; SetScrollY(result->Window, scroll_target); } + else + { + ImRect rect_abs = WindowRectRelToAbs(result->Window, result->RectRel); + ScrollToRectEx(result->Window, rect_abs, g.NavMoveScrollFlags); + } } if (g.NavWindow != result->Window) @@ -11786,45 +11218,35 @@ void ImGui::NavMoveRequestApplyResult() } if (g.ActiveId != result->ID) ClearActiveID(); - - // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId) - // PageUp/PageDown however sets always set NavJustMovedTo (vs Home/End which doesn't) mimicking Windows behavior. - if ((g.NavId != result->ID || (g.NavMoveFlags & ImGuiNavMoveFlags_IsPageMove)) && (g.NavMoveFlags & ImGuiNavMoveFlags_NoSelect) == 0) + if (g.NavId != result->ID) { + // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId) g.NavJustMovedToId = result->ID; g.NavJustMovedToFocusScopeId = result->FocusScopeId; g.NavJustMovedToKeyMods = g.NavMoveKeyMods; } - // Apply new NavID/Focus + // Focus IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); - ImVec2 preferred_scoring_pos_rel = g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer]; SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); - // Restore last preferred position for current axis - // (storing in RootWindowForNav-> as the info is desirable at the beginning of a Move Request. In theory all storage should use RootWindowForNav..) - if ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) == 0) + // Tabbing: Activates Inputable or Focus non-Inputable + if ((g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && (result->InFlags & ImGuiItemFlags_Inputable)) { - preferred_scoring_pos_rel[axis] = result->RectRel.GetCenter()[axis]; - g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer] = preferred_scoring_pos_rel; + g.NavNextActivateId = result->ID; + g.NavNextActivateFlags = ImGuiActivateFlags_PreferInput | ImGuiActivateFlags_TryToPreserveState; + g.NavMoveFlags |= ImGuiNavMoveFlags_DontSetNavHighlight; } - // Tabbing: Activates Inputable, otherwise only Focus - if ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && (result->InFlags & ImGuiItemFlags_Inputable) == 0) - g.NavMoveFlags &= ~ImGuiNavMoveFlags_Activate; - // Activate if (g.NavMoveFlags & ImGuiNavMoveFlags_Activate) { g.NavNextActivateId = result->ID; g.NavNextActivateFlags = ImGuiActivateFlags_None; - g.NavMoveFlags |= ImGuiNavMoveFlags_NoSetNavHighlight; - if (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) - g.NavNextActivateFlags |= ImGuiActivateFlags_PreferInput | ImGuiActivateFlags_TryToPreserveState; } // Enable nav highlight - if ((g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavHighlight) == 0) + if ((g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0) NavRestoreHighlightAfterMove(); } @@ -11897,7 +11319,7 @@ static float ImGui::NavUpdatePageUpPageDown() if (g.NavLayer != ImGuiNavLayer_Main) NavRestoreLayer(ImGuiNavLayer_Main); - if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY) + if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll) { // Fallback manual-scroll when window has no navigable item if (IsKeyPressed(ImGuiKey_PageUp, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat)) @@ -11919,14 +11341,14 @@ static float ImGui::NavUpdatePageUpPageDown() nav_scoring_rect_offset_y = -page_offset_y; g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item) g.NavMoveClipDir = ImGuiDir_Up; - g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet | ImGuiNavMoveFlags_IsPageMove; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; } else if (IsKeyPressed(ImGuiKey_PageDown, true)) { nav_scoring_rect_offset_y = +page_offset_y; g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item) g.NavMoveClipDir = ImGuiDir_Down; - g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet | ImGuiNavMoveFlags_IsPageMove; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; } else if (home_pressed) { @@ -11965,7 +11387,8 @@ static void ImGui::NavEndFrame() // Perform wrap-around in menus // FIXME-NAV: Wrap may need to apply a weight bias on the other axis. e.g. 4x4 grid with 2 last items missing on last item won't handle LoopY/WrapY correctly. // FIXME-NAV: Wrap (not Loop) support could be handled by the scoring function and then WrapX would function without an extra frame. - if (g.NavWindow && NavMoveRequestButNoResultYet() && (g.NavMoveFlags & ImGuiNavMoveFlags_WrapMask_) && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) + const ImGuiNavMoveFlags wanted_flags = ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY; + if (g.NavWindow && NavMoveRequestButNoResultYet() && (g.NavMoveFlags & wanted_flags) && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) NavUpdateCreateWrappingRequest(); } @@ -11977,9 +11400,7 @@ static void ImGui::NavUpdateCreateWrappingRequest() bool do_forward = false; ImRect bb_rel = window->NavRectRel[g.NavLayer]; ImGuiDir clip_dir = g.NavMoveDir; - const ImGuiNavMoveFlags move_flags = g.NavMoveFlags; - //const ImGuiAxis move_axis = (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) { bb_rel.Min.x = bb_rel.Max.x = window->ContentSize.x + window->WindowPadding.x; @@ -12023,8 +11444,6 @@ static void ImGui::NavUpdateCreateWrappingRequest() if (!do_forward) return; window->NavRectRel[g.NavLayer] = bb_rel; - NavClearPreferredPosForAxis(ImGuiAxis_X); - NavClearPreferredPosForAxis(ImGuiAxis_Y); NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags); } @@ -12078,7 +11497,7 @@ static void ImGui::NavUpdateWindowing() bool apply_toggle_layer = false; ImGuiWindow* modal_window = GetTopMostPopupModal(); - bool allow_windowing = (modal_window == NULL); // FIXME: This prevent CTRL+TAB from being usable with windows that are inside the Begin-stack of that modal. + bool allow_windowing = (modal_window == NULL); if (!allow_windowing) g.NavWindowingTarget = NULL; @@ -12091,11 +11510,10 @@ static void ImGui::NavUpdateWindowing() } // Start CTRL+Tab or Square+L/R window selection - const ImGuiID owner_id = ImHashStr("###NavUpdateWindowing"); const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; - const bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, owner_id, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways); - const bool keyboard_prev_window = allow_windowing && g.ConfigNavWindowingKeyPrev && Shortcut(g.ConfigNavWindowingKeyPrev, owner_id, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways); + const bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways); + const bool keyboard_prev_window = allow_windowing && g.ConfigNavWindowingKeyPrev && Shortcut(g.ConfigNavWindowingKeyPrev, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways); const bool start_windowing_with_gamepad = allow_windowing && nav_gamepad_active && !g.NavWindowingTarget && IsKeyPressed(ImGuiKey_NavGamepadMenu, 0, ImGuiInputFlags_None); const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && (keyboard_next_window || keyboard_prev_window); // Note: enabled even without NavEnableKeyboard! if (start_windowing_with_gamepad || start_windowing_with_keyboard) @@ -12106,10 +11524,6 @@ static void ImGui::NavUpdateWindowing() g.NavWindowingAccumDeltaPos = g.NavWindowingAccumDeltaSize = ImVec2(0.0f, 0.0f); g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad; - - // Register ownership of our mods. Using ImGuiInputFlags_RouteGlobalHigh in the Shortcut() calls instead would probably be correct but may have more side-effects. - if (keyboard_next_window || keyboard_prev_window) - SetKeyOwnersForKeyChord((g.ConfigNavWindowingKeyNext | g.ConfigNavWindowingKeyPrev) & ImGuiMod_Mask_, owner_id); } // Gamepad update @@ -12183,9 +11597,9 @@ static void ImGui::NavUpdateWindowing() { ImVec2 nav_move_dir; if (g.NavInputSource == ImGuiInputSource_Keyboard && !io.KeyShift) - nav_move_dir = GetKeyMagnitude2d(ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow); + nav_move_dir = GetKeyVector2d(ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow); if (g.NavInputSource == ImGuiInputSource_Gamepad) - nav_move_dir = GetKeyMagnitude2d(ImGuiKey_GamepadLStickLeft, ImGuiKey_GamepadLStickRight, ImGuiKey_GamepadLStickUp, ImGuiKey_GamepadLStickDown); + nav_move_dir = GetKeyVector2d(ImGuiKey_GamepadLStickLeft, ImGuiKey_GamepadLStickRight, ImGuiKey_GamepadLStickUp, ImGuiKey_GamepadLStickDown); if (nav_move_dir.x != 0.0f || nav_move_dir.y != 0.0f) { const float NAV_MOVE_SPEED = 800.0f; @@ -12207,9 +11621,9 @@ static void ImGui::NavUpdateWindowing() { ClearActiveID(); NavRestoreHighlightAfterMove(); + apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); ClosePopupsOverWindow(apply_focus_window, false); - FocusWindow(apply_focus_window, ImGuiFocusRequestFlags_RestoreFocusedChild); - apply_focus_window = g.NavWindow; + FocusWindow(apply_focus_window); if (apply_focus_window->NavLastIds[0] == 0) NavInitWindow(apply_focus_window, false); @@ -12380,7 +11794,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) // Rely on keeping other window->LastItemXXX fields intact. source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect); KeepAliveID(source_id); - bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id, g.LastItemData.InFlags); + bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id); if (is_hovered && g.IO.MouseClicked[mouse_button]) { SetActiveID(source_id, window); @@ -12426,12 +11840,13 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) { // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. - bool ret = BeginTooltip(); - IM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin("##Hidden", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame(). - IM_UNUSED(ret); - + BeginTooltip(); if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) - SetWindowHiddendAndSkipItemsForCurrentFrame(g.CurrentWindow); + { + ImGuiWindow* tooltip_window = g.CurrentWindow; + tooltip_window->Hidden = tooltip_window->SkipItems = true; + tooltip_window->HiddenFramesCanSkipItems = 1; + } } if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) @@ -12580,13 +11995,12 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId); ImRect r = g.DragDropTargetRect; float r_surface = r.GetWidth() * r.GetHeight(); - if (r_surface > g.DragDropAcceptIdCurrRectSurface) - return NULL; - - g.DragDropAcceptFlags = flags; - g.DragDropAcceptIdCurr = g.DragDropTargetId; - g.DragDropAcceptIdCurrRectSurface = r_surface; - //IMGUI_DEBUG_LOG("AcceptDragDropPayload(): %08X: accept\n", g.DragDropTargetId); + if (r_surface <= g.DragDropAcceptIdCurrRectSurface) + { + g.DragDropAcceptFlags = flags; + g.DragDropAcceptIdCurr = g.DragDropTargetId; + g.DragDropAcceptIdCurrRectSurface = r_surface; + } // Render default drop visuals payload.Preview = was_accepted_previously; @@ -12595,11 +12009,10 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop window->DrawList->AddRect(r.Min - ImVec2(3.5f,3.5f), r.Max + ImVec2(3.5f, 3.5f), GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f); g.DragDropAcceptFrameCount = g.FrameCount; - payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting OS window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased() + payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting os window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased() if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) return NULL; - //IMGUI_DEBUG_LOG("AcceptDragDropPayload(): %08X: return payload\n", g.DragDropTargetId); return &payload; } @@ -12615,16 +12028,13 @@ const ImGuiPayload* ImGui::GetDragDropPayload() return (g.DragDropActive && g.DragDropPayload.DataFrameCount != -1) ? &g.DragDropPayload : NULL; } +// We don't really use/need this now, but added it for the sake of consistency and because we might need it later. void ImGui::EndDragDropTarget() { ImGuiContext& g = *GImGui; IM_ASSERT(g.DragDropActive); IM_ASSERT(g.DragDropWithinTarget); g.DragDropWithinTarget = false; - - // Clear drag and drop state payload right after delivery - if (g.DragDropPayload.Delivery) - ClearDragDrop(); } //----------------------------------------------------------------------------- @@ -12858,10 +12268,10 @@ void ImGui::LogButtons() #endif const bool log_to_file = Button("Log To File"); SameLine(); const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); - PushTabStop(false); + PushAllowKeyboardFocus(false); SetNextItemWidth(80.0f); SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL); - PopTabStop(); + PopAllowKeyboardFocus(); PopID(); // Start logging at the end of the function so that the buttons don't appear in the log @@ -12879,17 +12289,15 @@ void ImGui::LogButtons() //----------------------------------------------------------------------------- // - UpdateSettings() [Internal] // - MarkIniSettingsDirty() [Internal] +// - CreateNewWindowSettings() [Internal] +// - FindWindowSettings() [Internal] +// - FindOrCreateWindowSettings() [Internal] // - FindSettingsHandler() [Internal] // - ClearIniSettings() [Internal] // - LoadIniSettingsFromDisk() // - LoadIniSettingsFromMemory() // - SaveIniSettingsToDisk() // - SaveIniSettingsToMemory() -//----------------------------------------------------------------------------- -// - CreateNewWindowSettings() [Internal] -// - FindWindowSettingsByID() [Internal] -// - FindWindowSettingsByWindow() [Internal] -// - ClearWindowSettings() [Internal] // - WindowSettingsHandler_***() [Internal] //----------------------------------------------------------------------------- @@ -12936,6 +12344,44 @@ void ImGui::MarkIniSettingsDirty(ImGuiWindow* window) g.SettingsDirtyTimer = g.IO.IniSavingRate; } +ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) +{ + ImGuiContext& g = *GImGui; + +#if !IMGUI_DEBUG_INI_SETTINGS + // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() + // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier. + if (const char* p = strstr(name, "###")) + name = p; +#endif + const size_t name_len = strlen(name); + + // Allocate chunk + const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; + ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size); + IM_PLACEMENT_NEW(settings) ImGuiWindowSettings(); + settings->ID = ImHashStr(name, name_len); + memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator + + return settings; +} + +ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->ID == id) + return settings; + return NULL; +} + +ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name) +{ + if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name))) + return settings; + return CreateNewWindowSettings(name); +} + void ImGui::AddSettingsHandler(const ImGuiSettingsHandler* handler) { ImGuiContext& g = *GImGui; @@ -12960,7 +12406,6 @@ ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) return NULL; } -// Clear all settings (windows, tables, docking etc.) void ImGui::ClearIniSettings() { ImGuiContext& g = *GImGui; @@ -12982,7 +12427,6 @@ void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) } // Zero-tolerance, no error reporting, cheap .ini parsing -// Set ini_size==0 to let us use strlen(ini_data). Do not call this function with a 0 if your buffer is actually empty! void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) { ImGuiContext& g = *GImGui; @@ -13086,63 +12530,6 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) return g.SettingsIniData.c_str(); } -ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) -{ - ImGuiContext& g = *GImGui; - - if (g.IO.ConfigDebugIniSettings == false) - { - // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() - // Preserve the full string when ConfigDebugVerboseIniSettings is set to make .ini inspection easier. - if (const char* p = strstr(name, "###")) - name = p; - } - const size_t name_len = strlen(name); - - // Allocate chunk - const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; - ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size); - IM_PLACEMENT_NEW(settings) ImGuiWindowSettings(); - settings->ID = ImHashStr(name, name_len); - memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator - - return settings; -} - -// We don't provide a FindWindowSettingsByName() because Docking system doesn't always hold on names. -// This is called once per window .ini entry + once per newly instantiated window. -ImGuiWindowSettings* ImGui::FindWindowSettingsByID(ImGuiID id) -{ - ImGuiContext& g = *GImGui; - for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) - if (settings->ID == id && !settings->WantDelete) - return settings; - return NULL; -} - -// This is faster if you are holding on a Window already as we don't need to perform a search. -ImGuiWindowSettings* ImGui::FindWindowSettingsByWindow(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - if (window->SettingsOffset != -1) - return g.SettingsWindows.ptr_from_offset(window->SettingsOffset); - return FindWindowSettingsByID(window->ID); -} - -// This will revert window to its initial state, including enabling the ImGuiCond_FirstUseEver/ImGuiCond_Once conditions once more. -void ImGui::ClearWindowSettings(const char* name) -{ - //IMGUI_DEBUG_LOG("ClearWindowSettings('%s')\n", name); - ImGuiWindow* window = FindWindowByName(name); - if (window != NULL) - { - window->Flags |= ImGuiWindowFlags_NoSavedSettings; - InitOrLoadWindowSettings(window, NULL); - } - if (ImGuiWindowSettings* settings = window ? FindWindowSettingsByWindow(window) : FindWindowSettingsByID(ImHashStr(name))) - settings->WantDelete = true; -} - static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) { ImGuiContext& g = *ctx; @@ -13153,12 +12540,9 @@ static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandl static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) { - ImGuiID id = ImHashStr(name); - ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByID(id); - if (settings) - *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry - else - settings = ImGui::CreateNewWindowSettings(name); + ImGuiWindowSettings* settings = ImGui::FindOrCreateWindowSettings(name); + ImGuiID id = settings->ID; + *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry settings->ID = id; settings->WantApply = true; return (void*)settings; @@ -13198,7 +12582,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl if (window->Flags & ImGuiWindowFlags_NoSavedSettings) continue; - ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByWindow(window); + ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID); if (!settings) { settings = ImGui::CreateNewWindowSettings(window->Name); @@ -13209,15 +12593,12 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl settings->Size = ImVec2ih(window->SizeFull); settings->Collapsed = window->Collapsed; - settings->WantDelete = false; } // Write to text buffer buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) { - if (settings->WantDelete) - continue; const char* settings_name = settings->GetName(); buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); @@ -13305,9 +12686,9 @@ static void ImGui::UpdateViewportsNewFrame() // Win32 clipboard implementation // We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown() -static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) +static const char* GetClipboardTextFn_DefaultImpl(void*) { - ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + ImGuiContext& g = *GImGui; g.ClipboardHandlerData.clear(); if (!::OpenClipboard(NULL)) return NULL; @@ -13368,9 +12749,8 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text) } } -static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) +static const char* GetClipboardTextFn_DefaultImpl(void*) { - ImGuiContext& g = *(ImGuiContext*)user_data_ctx; if (!main_clipboard) PasteboardCreate(kPasteboardClipboard, &main_clipboard); PasteboardSynchronize(main_clipboard); @@ -13388,6 +12768,7 @@ static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) CFDataRef cf_data; if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr) { + ImGuiContext& g = *GImGui; g.ClipboardHandlerData.clear(); int length = (int)CFDataGetLength(cf_data); g.ClipboardHandlerData.resize(length + 1); @@ -13404,15 +12785,15 @@ static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) #else // Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers. -static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) +static const char* GetClipboardTextFn_DefaultImpl(void*) { - ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + ImGuiContext& g = *GImGui; return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin(); } -static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text) +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) { - ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + ImGuiContext& g = *GImGui; g.ClipboardHandlerData.clear(); const char* text_end = text + strlen(text); g.ClipboardHandlerData.resize((int)(text_end - text) + 1); @@ -13434,6 +12815,10 @@ static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatf { // Notify OS Input Method Editor of text input position HWND hwnd = (HWND)viewport->PlatformHandleRaw; +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (hwnd == 0) + hwnd = (HWND)ImGui::GetIO().ImeWindowHandle; +#endif if (hwnd == 0) return; @@ -13536,60 +12921,11 @@ static void RenderViewportsThumbnails() ImGui::Dummy(bb_full.GetSize() * SCALE); } -// Draw an arbitrary US keyboard layout to visualize translated keys -void ImGui::DebugRenderKeyboardPreview(ImDrawList* draw_list) -{ - const ImVec2 key_size = ImVec2(35.0f, 35.0f); - const float key_rounding = 3.0f; - const ImVec2 key_face_size = ImVec2(25.0f, 25.0f); - const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f); - const float key_face_rounding = 2.0f; - const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f); - const ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f); - const float key_row_offset = 9.0f; - - ImVec2 board_min = GetCursorScreenPos(); - ImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f); - ImVec2 start_pos = ImVec2(board_min.x + 5.0f - key_step.x, board_min.y); - - struct KeyLayoutData { int Row, Col; const char* Label; ImGuiKey Key; }; - const KeyLayoutData keys_to_display[] = - { - { 0, 0, "", ImGuiKey_Tab }, { 0, 1, "Q", ImGuiKey_Q }, { 0, 2, "W", ImGuiKey_W }, { 0, 3, "E", ImGuiKey_E }, { 0, 4, "R", ImGuiKey_R }, - { 1, 0, "", ImGuiKey_CapsLock }, { 1, 1, "A", ImGuiKey_A }, { 1, 2, "S", ImGuiKey_S }, { 1, 3, "D", ImGuiKey_D }, { 1, 4, "F", ImGuiKey_F }, - { 2, 0, "", ImGuiKey_LeftShift },{ 2, 1, "Z", ImGuiKey_Z }, { 2, 2, "X", ImGuiKey_X }, { 2, 3, "C", ImGuiKey_C }, { 2, 4, "V", ImGuiKey_V } - }; - - // Elements rendered manually via ImDrawList API are not clipped automatically. - // While not strictly necessary, here IsItemVisible() is used to avoid rendering these shapes when they are out of view. - Dummy(board_max - board_min); - if (!IsItemVisible()) - return; - draw_list->PushClipRect(board_min, board_max, true); - for (int n = 0; n < IM_ARRAYSIZE(keys_to_display); n++) - { - const KeyLayoutData* key_data = &keys_to_display[n]; - ImVec2 key_min = ImVec2(start_pos.x + key_data->Col * key_step.x + key_data->Row * key_row_offset, start_pos.y + key_data->Row * key_step.y); - ImVec2 key_max = key_min + key_size; - draw_list->AddRectFilled(key_min, key_max, IM_COL32(204, 204, 204, 255), key_rounding); - draw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding); - ImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y); - ImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y); - draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f); - draw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding); - ImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y); - draw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label); - if (IsKeyDown(key_data->Key)) - draw_list->AddRectFilled(key_min, key_max, IM_COL32(255, 0, 0, 128), key_rounding); - } - draw_list->PopClipRect(); -} - // Helper tool to diagnose between text encoding issues and font loading issues. Pass your UTF-8 string and verify that there are correct. void ImGui::DebugTextEncoding(const char* str) { Text("Text: \"%s\"", str); - if (!BeginTable("##DebugTextEncoding", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable)) + if (!BeginTable("list", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit)) return; TableSetupColumn("Offset"); TableSetupColumn("UTF-8"); @@ -13625,8 +12961,9 @@ void ImGui::DebugTextEncoding(const char* str) static void MetricsHelpMarker(const char* desc) { ImGui::TextDisabled("(?)"); - if (ImGui::BeginItemTooltip()) + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) { + ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); ImGui::TextUnformatted(desc); ImGui::PopTextWrapPos(); @@ -13644,13 +12981,10 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) DebugNodeFont(font); PopID(); } - if (TreeNode("Font Atlas", "Font Atlas (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) + if (TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) { - ImGuiContext& g = *GImGui; - ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; - Checkbox("Tint with Text Color", &cfg->ShowAtlasTintedWithTextColor); // Using text color ensure visibility of core atlas data, but will alter custom colored icons - ImVec4 tint_col = cfg->ShowAtlasTintedWithTextColor ? GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); - ImVec4 border_col = GetStyleColorVec4(ImGuiCol_Border); + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col); TreePop(); } @@ -13707,8 +13041,8 @@ void ImGui::ShowMetricsWindow(bool* p_open) else if (rect_type == TRT_ColumnsClipRect) { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; } else if (rect_type == TRT_ColumnsContentHeadersUsed){ ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); } // Note: y1/y2 not always accurate else if (rect_type == TRT_ColumnsContentHeadersIdeal){ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); } - else if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight); } - else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); } + else if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); } + else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); } IM_ASSERT(0); return ImRect(); } @@ -13720,7 +13054,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) else if (rect_type == WRT_InnerRect) { return window->InnerRect; } else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; } else if (rect_type == WRT_WorkRect) { return window->WorkRect; } - else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } + else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } else if (rect_type == WRT_ContentIdeal) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSizeIdeal); } else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; } IM_ASSERT(0); @@ -13822,10 +13156,6 @@ void ImGui::ShowMetricsWindow(bool* p_open) } } - Checkbox("Debug Begin/BeginChild return value", &io.ConfigDebugBeginReturnValueLoop); - SameLine(); - MetricsHelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running."); - TreePop(); } @@ -13855,7 +13185,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) // DrawLists int drawlist_count = 0; for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) - drawlist_count += g.Viewports[viewport_i]->DrawDataP.CmdLists.Size; + drawlist_count += g.Viewports[viewport_i]->DrawDataBuilder.GetDrawListCount(); if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count)) { Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh); @@ -13863,8 +13193,9 @@ void ImGui::ShowMetricsWindow(bool* p_open) for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) { ImGuiViewportP* viewport = g.Viewports[viewport_i]; - for (int draw_list_i = 0; draw_list_i < viewport->DrawDataP.CmdLists.Size; draw_list_i++) - DebugNodeDrawList(NULL, viewport, viewport->DrawDataP.CmdLists[draw_list_i], "DrawList"); + for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++) + for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++) + DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList"); } TreePop(); } @@ -13956,12 +13287,11 @@ void ImGui::ShowMetricsWindow(bool* p_open) Text("\"%s\"", g.IO.IniFilename); else TextUnformatted(""); - Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings); Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer); if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size)) { for (int n = 0; n < g.SettingsHandlers.Size; n++) - BulletText("\"%s\"", g.SettingsHandlers[n].TypeName); + BulletText("%s", g.SettingsHandlers[n].TypeName); TreePop(); } if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size())) @@ -13989,97 +13319,41 @@ void ImGui::ShowMetricsWindow(bool* p_open) TreePop(); } - if (TreeNode("Inputs")) + if (TreeNode("Key Owners & Shortcut Routing")) { - Text("KEYBOARD/GAMEPAD/MOUSE KEYS"); - { - // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends. - // User code should never have to go through such hoops! You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. - Indent(); -#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO - struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; -#else - struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array - //Text("Legacy raw:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { SameLine(); Text("\"%s\" %d", GetKeyName(key), key); } } -#endif - Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); } - Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } - Text("Keys released:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } - Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); - Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; SameLine(); Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. - DebugRenderKeyboardPreview(GetWindowDrawList()); - Unindent(); - } - - Text("MOUSE STATE"); - { - Indent(); - if (IsMousePosValid()) - Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); - else - Text("Mouse pos: "); - Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); - int count = IM_ARRAYSIZE(io.MouseDown); - Text("Mouse down:"); for (int i = 0; i < count; i++) if (IsMouseDown(i)) { SameLine(); Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } - Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (IsMouseClicked(i)) { SameLine(); Text("b%d (%d)", i, io.MouseClickedCount[i]); } - Text("Mouse released:"); for (int i = 0; i < count; i++) if (IsMouseReleased(i)) { SameLine(); Text("b%d", i); } - Text("Mouse wheel: %.1f", io.MouseWheel); - Text("MouseStationaryTimer: %.2f", g.MouseStationaryTimer); - Text("Mouse source: %s", GetMouseSourceName(io.MouseSource)); - Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused - Unindent(); - } - - Text("MOUSE WHEELING"); - { - Indent(); - Text("WheelingWindow: '%s'", g.WheelingWindow ? g.WheelingWindow->Name : "NULL"); - Text("WheelingWindowReleaseTimer: %.2f", g.WheelingWindowReleaseTimer); - Text("WheelingAxisAvg[] = { %.3f, %.3f }, Main Axis: %s", g.WheelingAxisAvg.x, g.WheelingAxisAvg.y, (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? "X" : (g.WheelingAxisAvg.x < g.WheelingAxisAvg.y) ? "Y" : ""); - Unindent(); - } - - Text("KEY OWNERS"); + TextUnformatted("Key Owners:"); + if (BeginListBox("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 8))) { - Indent(); - if (BeginListBox("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6))) + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { - for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) - { - ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); - if (owner_data->OwnerCurr == ImGuiKeyOwner_None) - continue; - Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr, - owner_data->LockUntilRelease ? " LockUntilRelease" : owner_data->LockThisFrame ? " LockThisFrame" : ""); - DebugLocateItemOnHover(owner_data->OwnerCurr); - } - EndListBox(); + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); + if (owner_data->OwnerCurr == ImGuiKeyOwner_None) + continue; + Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr, + owner_data->LockUntilRelease ? " LockUntilRelease" : owner_data->LockThisFrame ? " LockThisFrame" : ""); + DebugLocateItemOnHover(owner_data->OwnerCurr); } - Unindent(); + EndListBox(); } - Text("SHORTCUT ROUTING"); + TextUnformatted("Shortcut Routing:"); + if (BeginListBox("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 8))) { - Indent(); - if (BeginListBox("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6))) + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { - for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; + for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; ) { - ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; - for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; ) - { - char key_chord_name[64]; - ImGuiKeyRoutingData* routing_data = &rt->Entries[idx]; - GetKeyChordName(key | routing_data->Mods, key_chord_name, IM_ARRAYSIZE(key_chord_name)); - Text("%s: 0x%08X", key_chord_name, routing_data->RoutingCurr); - DebugLocateItemOnHover(routing_data->RoutingCurr); - idx = routing_data->NextEntryIndex; - } + char key_chord_name[64]; + ImGuiKeyRoutingData* routing_data = &rt->Entries[idx]; + GetKeyChordName(key | routing_data->Mods, key_chord_name, IM_ARRAYSIZE(key_chord_name)); + Text("%s: 0x%08X", key_chord_name, routing_data->RoutingCurr); + DebugLocateItemOnHover(routing_data->RoutingCurr); + idx = routing_data->NextEntryIndex; } - EndListBox(); } - Text("(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask); - Unindent(); + EndListBox(); } + Text("(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask); TreePop(); } @@ -14100,7 +13374,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); Text("ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: %X", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask); Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame - Text("HoverItemDelayId: 0x%08X, Timer: %.2f, ClearTimer: %.2f", g.HoverItemDelayId, g.HoverItemDelayTimer, g.HoverItemDelayClearTimer); + Text("HoverDelayId: 0x%08X, Timer: %.2f, ClearTimer: %.2f", g.HoverDelayId, g.HoverDelayTimer, g.HoverDelayClearTimer); Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); DebugLocateItemOnHover(g.DragDropPayload.SourceId); Unindent(); @@ -14112,7 +13386,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) DebugLocateItemOnHover(g.NavId); Text("NavInputSource: %s", GetInputSourceName(g.NavInputSource)); Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); - Text("NavActivateId/DownId/PressedId: %08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId); + Text("NavActivateId/DownId/PressedId/InputId: %08X/%08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId, g.NavActivateInputId); Text("NavActivateFlags: %04X", g.NavActivateFlags); Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId); @@ -14196,10 +13470,9 @@ void ImGui::DebugNodeColumns(ImGuiOldColumns* columns) } // [DEBUG] Display contents of ImDrawList -void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label) +void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label) { ImGuiContext& g = *GImGui; - IM_UNUSED(viewport); // Used in docking branch ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; int cmd_count = draw_list->CmdBuffer.Size; if (cmd_count > 0 && draw_list->CmdBuffer.back().ElemCount == 0 && draw_list->CmdBuffer.back().UserCallback == NULL) @@ -14397,8 +13670,9 @@ void ImGui::DebugNodeFont(ImFont* font) if (!glyph) continue; font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); - if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip()) + if (IsMouseHoveringRect(cell_p1, cell_p2)) { + BeginTooltip(); DebugNodeFontGlyph(font, glyph); EndTooltip(); } @@ -14442,11 +13716,13 @@ void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label) char* p = buf; const char* buf_end = buf + IM_ARRAYSIZE(buf); const bool is_active = (tab_bar->PrevFrameVisible >= GetFrameCount() - 2); - p += ImFormatString(p, buf_end - p, "%s 0x%08X (%d tabs)%s {", label, tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*"); + p += ImFormatString(p, buf_end - p, "%s 0x%08X (%d tabs)%s", label, tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*"); + p += ImFormatString(p, buf_end - p, " { "); for (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; - p += ImFormatString(p, buf_end - p, "%s'%s'", tab_n > 0 ? ", " : "", TabBarGetTabName(tab_bar, tab)); + p += ImFormatString(p, buf_end - p, "%s'%s'", + tab_n > 0 ? ", " : "", (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "???"); } p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } "); if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } @@ -14463,12 +13739,12 @@ void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label) { for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) { - ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; PushID(tab); if (SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2); if (SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine(); Text("%02d%c Tab 0x%08X '%s' Offset: %.2f, Width: %.2f/%.2f", - tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, TabBarGetTabName(tab_bar, tab), tab->Offset, tab->Width, tab->ContentWidth); + tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "???", tab->Offset, tab->Width, tab->ContentWidth); PopID(); } TreePop(); @@ -14488,8 +13764,9 @@ void ImGui::DebugNodeViewport(ImGuiViewportP* viewport) (flags & ImGuiViewportFlags_IsPlatformWindow) ? " IsPlatformWindow" : "", (flags & ImGuiViewportFlags_IsPlatformMonitor) ? " IsPlatformMonitor" : "", (flags & ImGuiViewportFlags_OwnedByApp) ? " OwnedByApp" : ""); - for (int draw_list_i = 0; draw_list_i < viewport->DrawDataP.CmdLists.Size; draw_list_i++) - DebugNodeDrawList(NULL, viewport, viewport->DrawDataP.CmdLists[draw_list_i], "DrawList"); + for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++) + for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++) + DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList"); TreePop(); } } @@ -14517,7 +13794,7 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) TextDisabled("Note: some memory buffers have been compacted/freed."); ImGuiWindowFlags flags = window->Flags; - DebugNodeDrawList(window, window->Viewport, window->DrawList, "DrawList"); + DebugNodeDrawList(window, window->DrawList, "DrawList"); BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f) Ideal (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y, window->ContentSizeIdeal.x, window->ContentSizeIdeal.y); BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags, (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", @@ -14535,9 +13812,6 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y); DebugLocateItemOnHover(window->NavLastIds[layer]); } - const ImVec2* pr = window->NavPreferredScoringPosRel; - for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++) - BulletText("NavPreferredScoringPosRel[%d] = {%.1f,%.1f)", layer, (pr[layer].x == FLT_MAX ? -99999.0f : pr[layer].x), (pr[layer].y == FLT_MAX ? -99999.0f : pr[layer].y)); // Display as 99999.0f so it looks neater. BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); } if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); } @@ -14554,12 +13828,8 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings) { - if (settings->WantDelete) - BeginDisabled(); Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d", settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed); - if (settings->WantDelete) - EndDisabled(); } void ImGui::DebugNodeWindowsList(ImVector* windows, const char* label) @@ -14627,13 +13897,14 @@ void ImGui::ShowDebugLogWindow(bool* p_open) return; } - CheckboxFlags("All", &g.DebugLogFlags, ImGuiDebugLogFlags_EventMask_); + AlignTextToFramePadding(); + Text("Log events:"); + SameLine(); CheckboxFlags("All", &g.DebugLogFlags, ImGuiDebugLogFlags_EventMask_); SameLine(); CheckboxFlags("ActiveId", &g.DebugLogFlags, ImGuiDebugLogFlags_EventActiveId); SameLine(); CheckboxFlags("Focus", &g.DebugLogFlags, ImGuiDebugLogFlags_EventFocus); SameLine(); CheckboxFlags("Popup", &g.DebugLogFlags, ImGuiDebugLogFlags_EventPopup); SameLine(); CheckboxFlags("Nav", &g.DebugLogFlags, ImGuiDebugLogFlags_EventNav); - SameLine(); if (CheckboxFlags("Clipper", &g.DebugLogFlags, ImGuiDebugLogFlags_EventClipper)) { g.DebugLogClipperAutoDisableFrames = 2; } if (IsItemHovered()) SetTooltip("Clipper log auto-disabled after 2 frames"); - //SameLine(); CheckboxFlags("Selection", &g.DebugLogFlags, ImGuiDebugLogFlags_EventSelection); + SameLine(); CheckboxFlags("Clipper", &g.DebugLogFlags, ImGuiDebugLogFlags_EventClipper); SameLine(); CheckboxFlags("IO", &g.DebugLogFlags, ImGuiDebugLogFlags_EventIO); if (SmallButton("Clear")) @@ -14656,7 +13927,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) TextUnformatted(line_begin, line_end); ImRect text_rect = g.LastItemData.Rect; if (IsItemHovered()) - for (const char* p = line_begin; p <= line_end - 10; p++) + for (const char* p = line_begin; p < line_end - 10; p++) { ImGuiID id = 0; if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1) @@ -14734,8 +14005,7 @@ void ImGui::UpdateDebugToolItemPicker() if (change_mapping && IsMouseClicked(mouse_button)) g.DebugItemPickerMouseButton = (ImU8)mouse_button; SetNextWindowBgAlpha(0.70f); - if (!BeginTooltip()) - return; + BeginTooltip(); Text("HoveredId: 0x%08X", hovered_id); Text("Press ESC to abort picking."); const char* mouse_button_names[] = { "Left", "Right", "Middle" }; @@ -14933,7 +14203,7 @@ void ImGui::ShowStackToolWindow(bool* p_open) void ImGui::ShowMetricsWindow(bool*) {} void ImGui::ShowFontAtlas(ImFontAtlas*) {} void ImGui::DebugNodeColumns(ImGuiOldColumns*) {} -void ImGui::DebugNodeDrawList(ImGuiWindow*, ImGuiViewportP*, const ImDrawList*, const char*) {} +void ImGui::DebugNodeDrawList(ImGuiWindow*, const ImDrawList*, const char*) {} void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} void ImGui::DebugNodeFont(ImFont*) {} void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {} diff --git a/3rdparty/bgfx/3rdparty/dear-imgui/imgui.h b/3rdparty/bgfx/3rdparty/dear-imgui/imgui.h index 06f724b8e7d..a626c79f4b0 100644 --- a/3rdparty/bgfx/3rdparty/dear-imgui/imgui.h +++ b/3rdparty/bgfx/3rdparty/dear-imgui/imgui.h @@ -1,32 +1,29 @@ -// dear imgui, v1.89.8 WIP +// dear imgui, v1.89.1 WIP // (headers) // Help: -// - Read FAQ at http://dearimgui.com/faq +// - Read FAQ at http://dearimgui.org/faq // - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. // Read imgui.cpp for details, links and comments. // Resources: -// - FAQ http://dearimgui.com/faq -// - Homepage https://github.com/ocornut/imgui +// - FAQ http://dearimgui.org/faq +// - Homepage & latest https://github.com/ocornut/imgui // - Releases & changelog https://github.com/ocornut/imgui/releases -// - Gallery https://github.com/ocornut/imgui/issues/6478 (please post your screenshots/video there!) +// - Gallery https://github.com/ocornut/imgui/issues/5243 (please post your screenshots/video there!) // - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) -// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started // - Glossary https://github.com/ocornut/imgui/wiki/Glossary // - Issues & support https://github.com/ocornut/imgui/issues -// - Tests & Automation https://github.com/ocornut/imgui_test_engine // Getting Started? -// - Read https://github.com/ocornut/imgui/wiki/Getting-Started -// - For first-time users having issues compiling/linking/running/loading fonts: +// - For first-time users having issues compiling/linking/running or issues loading fonts: // please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. // Library Version -// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.89.8 WIP" -#define IMGUI_VERSION_NUM 18974 +// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') +#define IMGUI_VERSION "1.89.1 WIP" +#define IMGUI_VERSION_NUM 18903 #define IMGUI_HAS_TABLE /* @@ -40,7 +37,7 @@ Index of this file: // [SECTION] ImGuiStyle // [SECTION] ImGuiIO // [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) -// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) +// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) @@ -118,13 +115,10 @@ Index of this file: #endif #if defined(__clang__) #pragma clang diagnostic push -#if __has_warning("-Wunknown-warning-option") -#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' -#endif -#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' #pragma clang diagnostic ignored "-Wold-style-cast" +#if __has_warning("-Wzero-as-null-pointer-constant") #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" -#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter +#endif #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind @@ -173,7 +167,6 @@ struct ImGuiViewport; // A Platform Window (always only one in 'ma // In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. // With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. enum ImGuiKey : int; // -> enum ImGuiKey // Enum: A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value) -enum ImGuiMouseSource : int; // -> enum ImGuiMouseSource // Enum; A mouse input source identifier (Mouse, TouchScreen, Pen) typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type @@ -262,8 +255,8 @@ struct ImVec2 float x, y; constexpr ImVec2() : x(0.0f), y(0.0f) { } constexpr ImVec2(float _x, float _y) : x(_x), y(_y) { } - float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(void*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine. - float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const void*)(const char*)this)[idx]; } + float operator[] (size_t idx) const { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. + float& operator[] (size_t idx) { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. #ifdef IM_VEC2_CLASS_EXTRA IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. #endif @@ -412,8 +405,8 @@ namespace ImGui IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame(). IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. always use this if you modify the style after NewFrame(). IMGUI_API void PopStyleVar(int count = 1); - IMGUI_API void PushTabStop(bool tab_stop); // == tab stop enable. Allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets - IMGUI_API void PopTabStop(); + IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // == tab stop enable. Allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets + IMGUI_API void PopAllowKeyboardFocus(); IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. IMGUI_API void PopButtonRepeat(); @@ -426,7 +419,7 @@ namespace ImGui IMGUI_API void PopTextWrapPos(); // Style read access - // - Use the ShowStyleEditor() function to interactively see/edit the colors. + // - Use the style editor (ShowStyleEditor() function) to interactively see what the colors are) IMGUI_API ImFont* GetFont(); // get current font IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API @@ -467,7 +460,7 @@ namespace ImGui IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets) // ID stack/scopes - // Read the FAQ (docs/FAQ.md or http://dearimgui.com/faq) for more details about how ID are handled in dear imgui. + // Read the FAQ (docs/FAQ.md or http://dearimgui.org/faq) for more details about how ID are handled in dear imgui. // - Those questions are answered and impacted by understanding of the ID stack system: // - "Q: Why is my widget not reacting when I click on it?" // - "Q: How can I have widgets with an empty label?" @@ -500,7 +493,6 @@ namespace ImGui IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); - IMGUI_API void SeparatorText(const char* label); // currently: formatted text with an horizontal line // Widgets: Main // - Most widgets return true when the value has been changed or when pressed/selected @@ -671,21 +663,12 @@ namespace ImGui IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL // Tooltips - // - Tooltips are windows following the mouse. They do not take focus away. - // - A tooltip window can contain items of any types. SetTooltip() is a shortcut for the 'if (BeginTooltip()) { Text(...); EndTooltip(); }' idiom. - IMGUI_API bool BeginTooltip(); // begin/append a tooltip window. - IMGUI_API void EndTooltip(); // only call EndTooltip() if BeginTooltip()/BeginItemTooltip() returns true! - IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip. Often used after a ImGui::IsItemHovered() check. Override any previous call to SetTooltip(). + // - Tooltip are windows following the mouse. They do not take focus away. + IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of items). + IMGUI_API void EndTooltip(); + IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). override any previous call to SetTooltip(). IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); - // Tooltips: helpers for showing a tooltip when hovering an item - // - BeginItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_Tooltip) && BeginTooltip())' idiom. - // - SetItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_Tooltip)) { SetTooltip(...); }' idiom. - // - Where 'ImGuiHoveredFlags_Tooltip' itself is a shortcut to use 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on active input type. For mouse it defaults to 'ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort'. - IMGUI_API bool BeginItemTooltip(); // begin/append a tooltip window if preceding item was hovered. - IMGUI_API void SetItemTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip if preceeding item was hovered. override any previous call to SetTooltip(). - IMGUI_API void SetItemTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); - // Popups, Modals // - They block normal mouse hovering detection (and therefore most mouse interactions) behind them. // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. @@ -799,7 +782,6 @@ namespace ImGui IMGUI_API int GetColumnsCount(); // Tab Bars, Tabs - // - Note: Tabs are automatically created by the docking system (when in 'docking' branch). Use this to create tab bars/tabs yourself. IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true! IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0); // create a Tab. Returns true if the Tab is selected. @@ -847,9 +829,6 @@ namespace ImGui IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. - // Overlapping mode - IMGUI_API void SetNextItemAllowOverlap(); // allow next item to be overlapped by a subsequent item. Useful with invisible buttons, selectable, treenode covering an area where subsequent items may need to be added. Note that both Selectable() and TreeNode() have dedicated flags doing this. - // Item/Widgets Utilities and Query Functions // - Most of the functions are referring to the previous Item that has been submitted. // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. @@ -866,10 +845,10 @@ namespace ImGui IMGUI_API bool IsAnyItemHovered(); // is any item hovered? IMGUI_API bool IsAnyItemActive(); // is any item active? IMGUI_API bool IsAnyItemFocused(); // is any item focused? - IMGUI_API ImGuiID GetItemID(); // get ID of last item (~~ often same ImGui::GetID(label) beforehand) IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space) IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space) IMGUI_API ImVec2 GetItemRectSize(); // get size of last item + IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area. // Viewports // - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. @@ -902,11 +881,12 @@ namespace ImGui IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); - // Inputs Utilities: Keyboard/Mouse/Gamepad - // - the ImGuiKey enum contains all possible keyboard, mouse and gamepad inputs (e.g. ImGuiKey_A, ImGuiKey_MouseLeft, ImGuiKey_GamepadDpadUp...). - // - before v1.87, we used ImGuiKey to carry native/user indices as defined by each backends. About use of those legacy ImGuiKey values: - // - without IMGUI_DISABLE_OBSOLETE_KEYIO (legacy support): you can still use your legacy native/user indices (< 512) according to how your backend/engine stored them in io.KeysDown[], but need to cast them to ImGuiKey. - // - with IMGUI_DISABLE_OBSOLETE_KEYIO (this is the way forward): any use of ImGuiKey will assert with key < 512. GetKeyIndex() is pass-through and therefore deprecated (gone if IMGUI_DISABLE_OBSOLETE_KEYIO is defined). + // Inputs Utilities: Keyboard + // Without IMGUI_DISABLE_OBSOLETE_KEYIO: (legacy support) + // - For 'ImGuiKey key' you can still use your legacy native/user indices according to how your backend/engine stored them in io.KeysDown[]. + // With IMGUI_DISABLE_OBSOLETE_KEYIO: (this is the way forward) + // - Any use of 'ImGuiKey' will assert when key < 512 will be passed, previously reserved as native/user keys indices + // - GetKeyIndex() is pass-through and therefore deprecated (gone if IMGUI_DISABLE_OBSOLETE_KEYIO is defined) IMGUI_API bool IsKeyDown(ImGuiKey key); // is key being held. IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)? @@ -914,7 +894,7 @@ namespace ImGui IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names a provided for debugging purpose and are not meant to be saved persistently not compared. IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard); // Override io.WantCaptureKeyboard flag next frame (said flag is left for your application to handle, typically when true it instructs your app to ignore inputs). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard"; after the next NewFrame() call. - // Inputs Utilities: Mouse specific + // Inputs Utilities: Mouse // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. // - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold') @@ -1031,10 +1011,12 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) ImGuiInputTextFlags_CallbackEdit = 1 << 19, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) - ImGuiInputTextFlags_EscapeClearsAll = 1 << 20, // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert) + ImGuiInputTextFlags_EscapeClearsAll = 1 << 20, // Escape key clears content if not empty, and deactivate otherwise (constrast to default behavior of Escape to revert) - // Obsolete names - //ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior + // Obsolete names (will be removed soon) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior +#endif }; // Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() @@ -1043,7 +1025,7 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_None = 0, ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected ImGuiTreeNodeFlags_Framed = 1 << 1, // Draw frame with background (e.g. for CollapsingHeader) - ImGuiTreeNodeFlags_AllowOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one + ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open @@ -1057,10 +1039,6 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 14, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog, - -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 -#endif }; // Flags for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() functions. @@ -1094,11 +1072,7 @@ enum ImGuiSelectableFlags_ ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text - ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one - -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiSelectableFlags_AllowItemOverlap = ImGuiSelectableFlags_AllowOverlap, // Renamed in 1.89.7 -#endif + ImGuiSelectableFlags_AllowItemOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one }; // Flags for ImGui::BeginCombo() @@ -1304,30 +1278,16 @@ enum ImGuiHoveredFlags_ ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 5, // Return true even if a popup window is normally blocking access to this item/window //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 6, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. - ImGuiHoveredFlags_AllowWhenOverlappedByItem = 1 << 8, // IsItemHovered() only: Return true even if the item uses AllowOverlap mode and is overlapped by another hoverable item. - ImGuiHoveredFlags_AllowWhenOverlappedByWindow = 1 << 9, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window. - ImGuiHoveredFlags_AllowWhenDisabled = 1 << 10, // IsItemHovered() only: Return true even if the item is disabled - ImGuiHoveredFlags_NoNavOverride = 1 << 11, // IsItemHovered() only: Disable using gamepad/keyboard navigation state when active, always query mouse - ImGuiHoveredFlags_AllowWhenOverlapped = ImGuiHoveredFlags_AllowWhenOverlappedByItem | ImGuiHoveredFlags_AllowWhenOverlappedByWindow, + ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 8, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window + ImGuiHoveredFlags_AllowWhenDisabled = 1 << 9, // IsItemHovered() only: Return true even if the item is disabled + ImGuiHoveredFlags_NoNavOverride = 1 << 10, // Disable using gamepad/keyboard navigation state when active, always query mouse. ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows, - // Tooltips mode - // - typically used in IsItemHovered() + SetTooltip() sequence. - // - this is a shortcut to pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' where you can reconfigure desired behavior. - // e.g. 'TooltipHoveredFlagsForMouse' defaults to 'ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort'. - // - for frequently actioned or hovered items providing a tooltip, you want may to use ImGuiHoveredFlags_ForTooltip (stationary + delay) so the tooltip doesn't show too often. - // - for items which main purpose is to be hovered, or items with low affordance, or in less consistent apps, prefer no delay or shorter delay. - ImGuiHoveredFlags_ForTooltip = 1 << 12, // Shortcut for standard flags when using IsItemHovered() + SetTooltip() sequence. - - // (Advanced) Mouse Hovering delays. - // - generally you can use ImGuiHoveredFlags_ForTooltip to use application-standardized flags. - // - use those if you need specific overrides. - ImGuiHoveredFlags_Stationary = 1 << 13, // Require mouse to be stationary for style.HoverStationaryDelay (~0.15 sec) _at least one time_. After this, can move on same item/window. Using the stationary test tends to reduces the need for a long delay. - ImGuiHoveredFlags_DelayNone = 1 << 14, // IsItemHovered() only: Return true immediately (default). As this is the default you generally ignore this. - ImGuiHoveredFlags_DelayShort = 1 << 15, // IsItemHovered() only: Return true after style.HoverDelayShort elapsed (~0.15 sec) (shared between items) + requires mouse to be stationary for style.HoverStationaryDelay (once per item). - ImGuiHoveredFlags_DelayNormal = 1 << 16, // IsItemHovered() only: Return true after style.HoverDelayNormal elapsed (~0.40 sec) (shared between items) + requires mouse to be stationary for style.HoverStationaryDelay (once per item). - ImGuiHoveredFlags_NoSharedDelay = 1 << 17, // IsItemHovered() only: Disable shared delay system where moving from one item to the next keeps the previous timer for a short time (standard for tooltips with long delays) + // Hovering delays (for tooltips) + ImGuiHoveredFlags_DelayNormal = 1 << 11, // Return true after io.HoverDelayNormal elapsed (~0.30 sec) + ImGuiHoveredFlags_DelayShort = 1 << 12, // Return true after io.HoverDelayShort elapsed (~0.10 sec) + ImGuiHoveredFlags_NoSharedDelay = 1 << 13, // Disable shared delay system where moving from one item to the next keeps the previous timer for a short time (standard for tooltips with long delays) }; // Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() @@ -1335,7 +1295,7 @@ enum ImGuiDragDropFlags_ { ImGuiDragDropFlags_None = 0, // BeginDragDropSource() flags - ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // Disable preview tooltip. By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disables this behavior. + ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disables this behavior. ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disables this behavior so you can still call IsItemHovered() on the source item. ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item. ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. @@ -1387,11 +1347,9 @@ enum ImGuiSortDirection_ ImGuiSortDirection_Descending = 2 // Descending = 9->0, Z->A etc. }; -// A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value): can represent Keyboard, Mouse and Gamepad values. -// All our named keys are >= 512. Keys value 0 to 511 are left unused as legacy native/opaque key values (< 1.87). +// A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value) +// All our named keys are >= 512. Keys value 0 to 511 are left unused as legacy native/opaque key values (< 1.87) // Since >= 1.89 we increased typing (went from int to enum), some legacy code may need a cast to ImGuiKey. -// Read details about the 1.87 and 1.89 transition : https://github.com/ocornut/imgui/issues/4921 -// Note that "Keys" related to physical keys and are not the same concept as input "Characters", the later are submitted via io.AddInputCharacter(). enum ImGuiKey : int { // Keyboard @@ -1446,8 +1404,8 @@ enum ImGuiKey : int ImGuiKey_KeypadEnter, ImGuiKey_KeypadEqual, - // Gamepad (some of those are analog values, 0.0f to 1.0f) // NAVIGATION ACTION - // (download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets) + // Gamepad (some of those are analog values, 0.0f to 1.0f) // GAME NAVIGATION ACTION + // (download controller mapping PNG/PSD at http://dearimgui.org/controls_sheets) ImGuiKey_GamepadStart, // Menu (Xbox) + (Switch) Start/Options (PS) ImGuiKey_GamepadBack, // View (Xbox) - (Switch) Share (PS) ImGuiKey_GamepadFaceLeft, // X (Xbox) Y (Switch) Square (PS) // Tap: Toggle Menu. Hold: Windowing mode (Focus/Move/Resize windows) @@ -1473,7 +1431,7 @@ enum ImGuiKey : int ImGuiKey_GamepadRStickUp, // [Analog] ImGuiKey_GamepadRStickDown, // [Analog] - // Aliases: Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls) + // Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls) // - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be accessed via standard key API. ImGuiKey_MouseLeft, ImGuiKey_MouseRight, ImGuiKey_MouseMiddle, ImGuiKey_MouseX1, ImGuiKey_MouseX2, ImGuiKey_MouseWheelX, ImGuiKey_MouseWheelY, @@ -1490,25 +1448,28 @@ enum ImGuiKey : int // In practice: it's complicated; mods are often provided from different sources. Keyboard layout, IME, sticky keys and // backends tend to interfere and break that equivalence. The safer decision is to relay that ambiguity down to the end-user... ImGuiMod_None = 0, - ImGuiMod_Ctrl = 1 << 12, // Ctrl - ImGuiMod_Shift = 1 << 13, // Shift + ImGuiMod_Ctrl = 1 << 12, + ImGuiMod_Shift = 1 << 13, ImGuiMod_Alt = 1 << 14, // Option/Menu ImGuiMod_Super = 1 << 15, // Cmd/Super/Windows - ImGuiMod_Shortcut = 1 << 11, // Alias for Ctrl (non-macOS) _or_ Super (macOS). - ImGuiMod_Mask_ = 0xF800, // 5-bits + ImGuiMod_Mask_ = 0xF000, +#if defined(__APPLE__) + ImGuiMod_Shortcut = ImGuiMod_Super, +#else + ImGuiMod_Shortcut = ImGuiMod_Ctrl, +#endif // [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + the io.KeyMap[] array. // We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE) - // If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. ImGuiKey_NamedKey_BEGIN = 512, ImGuiKey_NamedKey_END = ImGuiKey_COUNT, ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, #ifdef IMGUI_DISABLE_OBSOLETE_KEYIO - ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys - ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index. + ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys + ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // First key stored in io.KeysData[0]. Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET). #else - ImGuiKey_KeysData_SIZE = ImGuiKey_COUNT, // Size of KeysData[]: hold legacy 0..512 keycodes + named keys - ImGuiKey_KeysData_OFFSET = 0, // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index. + ImGuiKey_KeysData_SIZE = ImGuiKey_COUNT, // Size of KeysData[]: hold legacy 0..512 keycodes + named keys + ImGuiKey_KeysData_OFFSET = 0, // First key stored in io.KeysData[0]. Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET). #endif #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS @@ -1533,7 +1494,7 @@ enum ImGuiNavInput enum ImGuiConfigFlags_ { ImGuiConfigFlags_None = 0, - ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. Enable full Tabbing + directional arrows + space/enter to activate. + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. Backend also needs to set ImGuiBackendFlags_HasGamepad. ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your backend, otherwise ImGui will react as if the mouse is jumping around back and forth. ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set. @@ -1649,9 +1610,6 @@ enum ImGuiStyleVar_ ImGuiStyleVar_TabRounding, // float TabRounding ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign - ImGuiStyleVar_SeparatorTextBorderSize,// float SeparatorTextBorderSize - ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign - ImGuiStyleVar_SeparatorTextPadding,// ImVec2 SeparatorTextPadding ImGuiStyleVar_COUNT }; @@ -1708,8 +1666,8 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV, - // Obsolete names - //ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] + // Obsolete names (will be removed) + // ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] }; // Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. @@ -1724,8 +1682,10 @@ enum ImGuiSliderFlags_ ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed. - // Obsolete names - //ImGuiSliderFlags_ClampOnInput = ImGuiSliderFlags_AlwaysClamp, // [renamed in 1.79] + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiSliderFlags_ClampOnInput = ImGuiSliderFlags_AlwaysClamp, // [renamed in 1.79] +#endif }; // Identify a mouse button. @@ -1755,18 +1715,6 @@ enum ImGuiMouseCursor_ ImGuiMouseCursor_COUNT }; -// Enumeration for AddMouseSourceEvent() actual source of Mouse Input data. -// Historically we use "Mouse" terminology everywhere to indicate pointer data, e.g. MousePos, IsMousePressed(), io.AddMousePosEvent() -// But that "Mouse" data can come from different source which occasionally may be useful for application to know about. -// You can submit a change of pointer type using io.AddMouseSourceEvent(). -enum ImGuiMouseSource : int -{ - ImGuiMouseSource_Mouse = 0, // Input is coming from an actual mouse. - ImGuiMouseSource_TouchScreen, // Input is coming from a touch screen (no hovering prior to initial press, less precise initial press aiming, dual-axis wheeling possible). - ImGuiMouseSource_Pen, // Input is coming from a pressure/magnetic pen (often used in conjunction with high-sampling rates). - ImGuiMouseSource_COUNT -}; - // Enumeration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions // Represent a condition. // Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. @@ -1916,9 +1864,6 @@ struct ImGuiStyle ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. - float SeparatorTextBorderSize; // Thickkness of border in SeparatorText() - ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). - ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. @@ -1929,14 +1874,6 @@ struct ImGuiStyle float CircleTessellationMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. ImVec4 Colors[ImGuiCol_COUNT]; - // Behaviors - // (It is possible to modify those fields mid-frame if specific behavior need it, unlike e.g. configuration fields in ImGuiIO) - float HoverStationaryDelay; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary. - float HoverDelayShort; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay. - float HoverDelayNormal; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). " - ImGuiHoveredFlags HoverFlagsForTooltipMouse;// Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse. - ImGuiHoveredFlags HoverFlagsForTooltipNav; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad. - IMGUI_API ImGuiStyle(); IMGUI_API void ScaleAllSizes(float scale_factor); }; @@ -1971,7 +1908,14 @@ struct ImGuiIO float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. const char* IniFilename; // = "imgui.ini" // Path to .ini file (important: default "imgui.ini" is relative to current working dir!). Set NULL to disable automatic .ini loading/saving or if you want to manually call LoadIniSettingsXXX() / SaveIniSettingsXXX() functions. const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). - void* UserData; // = NULL // Store your own data. + float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. + float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. + float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. + float KeyRepeatDelay; // = 0.275f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). + float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. + float HoverDelayNormal; // = 0.30 sec // Delay on hovering before IsItemHovered(ImGuiHoveredFlags_DelayNormal) returns true. + float HoverDelayShort; // = 0.10 sec // Delay on hovering before IsItemHovered(ImGuiHoveredFlags_DelayShort) returns true. + void* UserData; // = NULL // Store your own data for retrieval by callbacks. ImFontAtlas*Fonts; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. float FontGlobalScale; // = 1.0f // Global scale all fonts @@ -1990,33 +1934,6 @@ struct ImGuiIO bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. float ConfigMemoryCompactTimer; // = 60.0f // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable. - // Inputs Behaviors - // (other variables, ones which are expected to be tweaked within UI code, are exposed in ImGuiStyle) - float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. - float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. - float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. - float KeyRepeatDelay; // = 0.275f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). - float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. - - //------------------------------------------------------------------ - // Debug options - //------------------------------------------------------------------ - - // Tools to test correct Begin/End and BeginChild/EndChild behaviors. - // Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX() - // This is inconsistent with other BeginXXX functions and create confusion for many users. - // We expect to update the API eventually. In the meanwhile we provide tools to facilitate checking user-code behavior. - bool ConfigDebugBeginReturnValueOnce;// = false // First-time calls to Begin()/BeginChild() will return false. NEEDS TO BE SET AT APPLICATION BOOT TIME if you don't want to miss windows. - bool ConfigDebugBeginReturnValueLoop;// = false // Some calls to Begin()/BeginChild() will return false. Will cycle through window depths then repeat. Suggested use: add "io.ConfigDebugBeginReturnValue = io.KeyShift" in your main loop then occasionally press SHIFT. Windows should be flickering while running. - - // Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data. - // Backends may have other side-effects on focus loss, so this will reduce side-effects but not necessary remove all of them. - // Consider using e.g. Win32's IsDebuggerPresent() as an additional filter (or see ImOsIsDebuggerPresent() in imgui_test_engine/imgui_te_utils.cpp for a Unix compatible version). - bool ConfigDebugIgnoreFocusLoss; // = false // Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys() in input processing. - - // Options to audit .ini data - bool ConfigDebugIniSettings; // = false // Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower) - //------------------------------------------------------------------ // Platform Functions // (the imgui_impl_xxxx backend files are setting those up for you) @@ -2053,8 +1970,7 @@ struct ImGuiIO IMGUI_API void AddKeyAnalogEvent(ImGuiKey key, bool down, float v); // Queue a new key down/up event for analog values (e.g. ImGuiKey_Gamepad_ values). Dead-zones should be handled by the backend. IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered) IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change - IMGUI_API void AddMouseWheelEvent(float wheel_x, float wheel_y); // Queue a mouse wheel update. wheel_y<0: scroll down, wheel_y>0: scroll up, wheel_x<0: scroll right, wheel_x>0: scroll left. - IMGUI_API void AddMouseSourceEvent(ImGuiMouseSource source); // Queue a mouse source change (Mouse/TouchScreen/Pen) + IMGUI_API void AddMouseWheelEvent(float wh_x, float wh_y); // Queue a mouse wheel update IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window) IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue a new character input from a UTF-16 character, it can be a surrogate @@ -2062,11 +1978,8 @@ struct ImGuiIO IMGUI_API void SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index = -1); // [Optional] Specify index for legacy <1.87 IsKeyXXX() functions with native indices + specify native keycode, scancode. IMGUI_API void SetAppAcceptingEvents(bool accepting_events); // Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen. - IMGUI_API void ClearEventsQueue(); // Clear all incoming events. - IMGUI_API void ClearInputKeys(); // Clear current keyboard/mouse/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons. -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - IMGUI_API void ClearInputCharacters(); // [Obsolete] Clear the current frame text input buffer. Now included within ClearInputKeys(). -#endif + IMGUI_API void ClearInputCharacters(); // [Internal] Clear the text input buffer manually + IMGUI_API void ClearInputKeys(); // [Internal] Release all keys //------------------------------------------------------------------ // Output - Updated by NewFrame() or EndFrame()/Render() @@ -2102,23 +2015,20 @@ struct ImGuiIO // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! //------------------------------------------------------------------ - ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent). - // Main Input State // (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX functions above instead) // (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere) ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.) bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. - float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold SHIFT to turn vertical scroll into horizontal scroll. - float MouseWheelH; // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends. - ImGuiMouseSource MouseSource; // Mouse actual input peripheral (Mouse/TouchScreen/Pen). + float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. + float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends. bool KeyCtrl; // Keyboard modifier down: Control bool KeyShift; // Keyboard modifier down: Shift bool KeyAlt; // Keyboard modifier down: Alt bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows // Other state maintained from data above + IO function calls - ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. DOES NOT CONTAINS ImGuiMod_Shortcut which is pretranslated). Read-only, updated by NewFrame() + ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags). Read-only, updated by NewFrame() ImGuiKeyData KeysData[ImGuiKey_KeysData_SIZE]; // Key state for all known keys. Use IsKeyXXX() functions to access this. bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) @@ -2131,7 +2041,6 @@ struct ImGuiIO bool MouseReleased[5]; // Mouse button went from Down to !Down bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. bool MouseDownOwnedUnlessPopupClose[5]; // Track if button was clicked inside a dear imgui window. - bool MouseWheelRequestAxisSwap; // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system. float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) float MouseDownDurationPrev[5]; // Previous time the mouse button has been down float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds) @@ -2161,7 +2070,6 @@ struct ImGuiIO // - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. struct ImGuiInputTextCallbackData { - ImGuiContext* Ctx; // Parent UI context ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only void* UserData; // What user passed to InputText() // Read-only @@ -2246,7 +2154,7 @@ struct ImGuiTableSortSpecs }; //----------------------------------------------------------------------------- -// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) +// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) //----------------------------------------------------------------------------- // Helper: Unicode defines @@ -2386,7 +2294,6 @@ struct ImGuiStorage // - The clipper also handles various subtleties related to keyboard/gamepad navigation, wrapping etc. struct ImGuiListClipper { - ImGuiContext* Ctx; // Parent UI context int DisplayStart; // First item to display, updated by each call to Step() int DisplayEnd; // End of items to display (exclusive) int ItemsCount; // [Internal] Number of items @@ -2402,42 +2309,14 @@ struct ImGuiListClipper IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. - // Call IncludeRangeByIndices() *BEFORE* first call to Step() if you need a range of items to not be clipped, regardless of their visibility. - // (Due to alignment / padding of certain items it is possible that an extra item may be included on either end of the display range). - IMGUI_API void IncludeRangeByIndices(int item_begin, int item_end); // item_end is exclusive e.g. use (42, 42+1) to make item 42 never clipped. + // Call ForceDisplayRangeByIndices() before first call to Step() if you need a range of items to be displayed regardless of visibility. + IMGUI_API void ForceDisplayRangeByIndices(int item_min, int item_max); // item_max is exclusive e.g. use (42, 42+1) to make item 42 always visible BUT due to alignment/padding of certain items it is likely that an extra item may be included on either end of the display range. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - inline void ForceDisplayRangeByIndices(int item_begin, int item_end) { IncludeRangeByIndices(item_begin, item_end); } // [renamed in 1.89.6] - //inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79] + inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79] #endif }; -// Helpers: ImVec2/ImVec4 operators -// - It is important that we are keeping those disabled by default so they don't leak in user space. -// - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h) -// - You can use '#define IMGUI_DEFINE_MATH_OPERATORS' to import our operators, provided as a courtesy. -#ifdef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED -IM_MSVC_RUNTIME_CHECKS_OFF -static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } -static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } -static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } -static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } -static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } -static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } -static inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } -static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } -static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } -static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } -static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } -static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } -static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } -static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } -static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } -static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } -IM_MSVC_RUNTIME_CHECKS_RESTORE -#endif - // Helpers macros to generate 32-bit encoded colors // User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. #ifndef IM_COL32_R_SHIFT @@ -2471,8 +2350,8 @@ struct ImColor constexpr ImColor() { } constexpr ImColor(float r, float g, float b, float a = 1.0f) : Value(r, g, b, a) { } constexpr ImColor(const ImVec4& col) : Value(col) {} - constexpr ImColor(int r, int g, int b, int a = 255) : Value((float)r * (1.0f / 255.0f), (float)g * (1.0f / 255.0f), (float)b * (1.0f / 255.0f), (float)a* (1.0f / 255.0f)) {} - constexpr ImColor(ImU32 rgba) : Value((float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * (1.0f / 255.0f)) {} + ImColor(int r, int g, int b, int a = 255) { float sc = 1.0f / 255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; } + ImColor(ImU32 rgba) { float sc = 1.0f / 255.0f; Value.x = (float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; } inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } inline operator ImVec4() const { return Value; } @@ -2725,9 +2604,10 @@ struct ImDrawList inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index - // Obsolete names - //inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021) - //inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021) + inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021) +#endif // [Internal helpers] IMGUI_API void _ResetForNewFrame(); @@ -2747,20 +2627,18 @@ struct ImDrawList // as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList) struct ImDrawData { - bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. - int CmdListsCount; // Number of ImDrawList* to render (should always be == CmdLists.size) - int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size - int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size - ImVector CmdLists; // Array of ImDrawList* to render. The ImDrawLists are owned by ImGuiContext and only pointed to from here. - ImVec2 DisplayPos; // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport applications) - ImVec2 DisplaySize; // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications) - ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. - ImGuiViewport* OwnerViewport; // Viewport carrying the ImDrawData instance, might be of use to the renderer (generally not). + bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. + int CmdListsCount; // Number of ImDrawList* to render + int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size + int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size + ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. + ImVec2 DisplayPos; // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport applications) + ImVec2 DisplaySize; // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications) + ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. // Functions ImDrawData() { Clear(); } - IMGUI_API void Clear(); - IMGUI_API void AddDrawList(ImDrawList* draw_list); // Helper to add an external draw list into an existing ImDrawData. + void Clear() { memset(this, 0, sizeof(*this)); } // The ImDrawList are owned by ImGuiContext! IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. }; @@ -2776,12 +2654,12 @@ struct ImFontConfig bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). int FontNo; // 0 // Index of font within TTF/OTF file float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). - int OversampleH; // 2 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal so you can reduce this to 2 to save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis. bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. - const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). + const ImWchar* GlyphRanges; // NULL // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. @@ -2894,8 +2772,7 @@ struct ImFontAtlas //------------------------------------------- // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) - // NB: Make sure that your string are UTF-8 and NOT in your local code page. - // Read https://github.com/ocornut/imgui/blob/master/docs/FONTS.md/#about-utf-8-encoding for details. + // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details. // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin IMGUI_API const ImWchar* GetGlyphRangesGreek(); // Default + Greek and Coptic @@ -2935,7 +2812,6 @@ struct ImFontAtlas int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. - void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). // [Internal] // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. @@ -2984,10 +2860,8 @@ struct ImFont const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. ImWchar FallbackChar; // 2 // out // = FFFD/'?' // Character used if a glyph isn't found. - ImWchar EllipsisChar; // 2 // out // = '...'/'.'// Character used for ellipsis rendering. - short EllipsisCharCount; // 1 // out // 1 or 3 - float EllipsisWidth; // 4 // out // Width - float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 + ImWchar EllipsisChar; // 2 // out // = '...' // Character used for ellipsis rendering. + ImWchar DotChar; // 2 // out // = '.' // Character used for ellipsis rendering (if a single '...' character isn't found) bool DirtyLookupTables; // 1 // out // float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] @@ -3090,11 +2964,6 @@ namespace ImGui #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS namespace ImGui { - // OBSOLETED in 1.89.7 (from June 2023) - IMGUI_API void SetItemAllowOverlap(); // Use SetNextItemAllowOverlap() before item. - // OBSOLETED in 1.89.4 (from March 2023) - static inline void PushAllowKeyboardFocus(bool tab_stop) { PushTabStop(tab_stop); } - static inline void PopAllowKeyboardFocus() { PopTabStop(); } // OBSOLETED in 1.89 (from August 2022) IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // Use new ImageButton() signature (explicit item id, regular FramePadding) // OBSOLETED in 1.88 (from May 2022) @@ -3104,12 +2973,12 @@ namespace ImGui IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // Calculate coarse clipping for large list of evenly sized items. Prefer using ImGuiListClipper. // OBSOLETED in 1.85 (from August 2021) static inline float GetWindowContentRegionWidth() { return GetWindowContentRegionMax().x - GetWindowContentRegionMin().x; } + // OBSOLETED in 1.81 (from February 2021) + IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // Helper to calculate size from items_count and height_in_items + static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } + static inline void ListBoxFooter() { EndListBox(); } // Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) - //-- OBSOLETED in 1.81 (from February 2021) - //static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } - //static inline bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1) { float height = GetTextLineHeightWithSpacing() * ((height_in_items < 0 ? ImMin(items_count, 7) : height_in_items) + 0.25f) + GetStyle().FramePadding.y * 2.0f; return BeginListBox(label, ImVec2(0.0f, height)); } // Helper to calculate size from items_count and height_in_items - //static inline void ListBoxFooter() { EndListBox(); } //-- OBSOLETED in 1.79 (from August 2020) //static inline void OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry! //-- OBSOLETED in 1.78 (from June 2020): Old drag/sliders functions that took a 'float power > 1.0f' argument instead of ImGuiSliderFlags_Logarithmic. See github.com/ocornut/imgui/issues/3361 for details. diff --git a/3rdparty/bgfx/3rdparty/dear-imgui/imgui_demo.cpp b/3rdparty/bgfx/3rdparty/dear-imgui/imgui_demo.cpp index 1f16bb9d66c..56058693377 100644 --- a/3rdparty/bgfx/3rdparty/dear-imgui/imgui_demo.cpp +++ b/3rdparty/bgfx/3rdparty/dear-imgui/imgui_demo.cpp @@ -1,12 +1,10 @@ -// dear imgui, v1.89.8 WIP +// dear imgui, v1.89.1 WIP // (demo code) // Help: -// - Read FAQ at http://dearimgui.com/faq +// - Read FAQ at http://dearimgui.org/faq +// - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. -// - Need help integrating Dear ImGui in your codebase? -// - Read Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started -// - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. // Read imgui.cpp for more details, documentation and comments. // Get the latest version at https://github.com/ocornut/imgui @@ -40,7 +38,7 @@ // - We try to declare static variables in the local scope, as close as possible to the code using them. // - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API. // - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided -// by imgui.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional +// by imgui_internal.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional // and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. // Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp. @@ -93,7 +91,11 @@ Index of this file: #include // sqrtf, powf, cosf, sinf, floorf, ceilf #include // vsnprintf, sscanf, printf #include // NULL, malloc, free, atoi +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else #include // intptr_t +#endif // Visual Studio warnings #ifdef _MSC_VER @@ -209,8 +211,9 @@ static void ShowDemoWindowInputs(); static void HelpMarker(const char* desc) { ImGui::TextDisabled("(?)"); - if (ImGui::BeginItemTooltip()) + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) { + ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); ImGui::TextUnformatted(desc); ImGui::PopTextWrapPos(); @@ -396,21 +399,23 @@ void ImGui::ShowDemoWindow(bool* p_open) IMGUI_DEMO_MARKER("Help"); if (ImGui::CollapsingHeader("Help")) { - ImGui::SeparatorText("ABOUT THIS DEMO:"); + ImGui::Text("ABOUT THIS DEMO:"); ImGui::BulletText("Sections below are demonstrating many aspects of the library."); ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" "and Metrics/Debugger (general purpose Dear ImGui debugging tool)."); + ImGui::Separator(); - ImGui::SeparatorText("PROGRAMMER GUIDE:"); + ImGui::Text("PROGRAMMER GUIDE:"); ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); ImGui::BulletText("See comments in imgui.cpp."); ImGui::BulletText("See example applications in the examples/ folder."); - ImGui::BulletText("Read the FAQ at http://www.dearimgui.com/faq/"); + ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/"); ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); + ImGui::Separator(); - ImGui::SeparatorText("USER GUIDE:"); + ImGui::Text("USER GUIDE:"); ImGui::ShowUserGuide(); } @@ -421,7 +426,6 @@ void ImGui::ShowDemoWindow(bool* p_open) if (ImGui::TreeNode("Configuration##2")) { - ImGui::SeparatorText("General"); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); ImGui::SameLine(); HelpMarker("Enable keyboard controls."); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); @@ -444,10 +448,6 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility."); ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue); ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates."); - ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); - ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); - - ImGui::SeparatorText("Widgets"); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive); @@ -457,23 +457,11 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); - ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors); + ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); + ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); ImGui::Text("Also see Style->Rendering for rendering options."); - - ImGui::SeparatorText("Debug"); - ImGui::BeginDisabled(); - ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); // . - ImGui::EndDisabled(); - ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover"); - ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop); - ImGui::SameLine(); HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running."); - ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss); - ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data."); - ImGui::Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings); - ImGui::SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower)."); - ImGui::TreePop(); - ImGui::Spacing(); + ImGui::Separator(); } IMGUI_DEMO_MARKER("Configuration/Backend Flags"); @@ -483,15 +471,15 @@ void ImGui::ShowDemoWindow(bool* p_open) "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" "Here we expose them as read-only fields to avoid breaking interactions with your backend."); - // FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright? - ImGui::BeginDisabled(); - ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad); - ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); - ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos); - ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset); - ImGui::EndDisabled(); + // Make a local copy to avoid modifying actual backend flags. + // FIXME: We don't use BeginDisabled() to keep label bright, maybe we need a BeginReadonly() equivalent.. + ImGuiBackendFlags backend_flags = io.BackendFlags; + ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &backend_flags, ImGuiBackendFlags_HasGamepad); + ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &backend_flags, ImGuiBackendFlags_HasMouseCursors); + ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &backend_flags, ImGuiBackendFlags_HasSetMousePos); + ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); ImGui::TreePop(); - ImGui::Spacing(); + ImGui::Separator(); } IMGUI_DEMO_MARKER("Configuration/Style"); @@ -500,7 +488,7 @@ void ImGui::ShowDemoWindow(bool* p_open) HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); ImGui::ShowStyleEditor(); ImGui::TreePop(); - ImGui::Spacing(); + ImGui::Separator(); } IMGUI_DEMO_MARKER("Configuration/Capture, Logging"); @@ -568,8 +556,6 @@ static void ShowDemoWindowWidgets() IMGUI_DEMO_MARKER("Widgets/Basic"); if (ImGui::TreeNode("Basic")) { - ImGui::SeparatorText("General"); - IMGUI_DEMO_MARKER("Widgets/Basic/Button"); static int clicked = 0; if (ImGui::Button("Button")) @@ -624,12 +610,19 @@ static void ShowDemoWindowWidgets() ImGui::SameLine(); ImGui::Text("%d", counter); - ImGui::Button("Tooltip"); - ImGui::SetItemTooltip("I am a tooltip"); - + ImGui::Separator(); ImGui::LabelText("label", "Value"); - ImGui::SeparatorText("Inputs"); + { + // Using the _simplified_ one-liner Combo() api here + // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. + IMGUI_DEMO_MARKER("Widgets/Basic/Combo"); + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; + static int item_current = 0; + ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); + ImGui::SameLine(); HelpMarker( + "Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API."); + } { // To wire InputText() with std::string or any other custom string type, @@ -673,8 +666,6 @@ static void ShowDemoWindowWidgets() ImGui::InputFloat3("input float3", vec4a); } - ImGui::SeparatorText("Drags"); - { IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat"); static int i1 = 50, i2 = 42; @@ -691,8 +682,6 @@ static void ShowDemoWindowWidgets() ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); } - ImGui::SeparatorText("Sliders"); - { IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat"); static int i1 = 0; @@ -715,12 +704,10 @@ static void ShowDemoWindowWidgets() static int elem = Element_Fire; const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; - ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here. + ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); } - ImGui::SeparatorText("Selectors/Pickers"); - { IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4"); static float col1[3] = { 1.0f, 0.0f, 0.2f }; @@ -735,17 +722,6 @@ static void ShowDemoWindowWidgets() ImGui::ColorEdit4("color 2", col2); } - { - // Using the _simplified_ one-liner Combo() api here - // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. - IMGUI_DEMO_MARKER("Widgets/Basic/Combo"); - const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; - static int item_current = 0; - ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); - ImGui::SameLine(); HelpMarker( - "Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API."); - } - { // Using the _simplified_ one-liner ListBox() api here // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. @@ -757,84 +733,39 @@ static void ShowDemoWindowWidgets() "Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); } - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Tooltips"); - if (ImGui::TreeNode("Tooltips")) - { - // Tooltips are windows following the mouse. They do not take focus away. - ImGui::SeparatorText("General"); - - // Typical use cases: - // - Short-form (text only): SetItemTooltip("Hello"); - // - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); } - - // - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); } - // - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); } - - HelpMarker( - "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n" - "We provide a helper SetItemTooltip() function to perform the two with standards flags."); - - ImVec2 sz = ImVec2(-FLT_MIN, 0.0f); - - ImGui::Button("Basic", sz); - ImGui::SetItemTooltip("I am a tooltip"); - - ImGui::Button("Fancy", sz); - if (ImGui::BeginItemTooltip()) { - ImGui::Text("I am a fancy tooltip"); - static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; - ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); - ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime())); - ImGui::EndTooltip(); - } - - ImGui::SeparatorText("Always On"); - - // Showcase NOT relying on a IsItemHovered() to emit a tooltip. - // Here the tooltip is always emitted when 'always_on == true'. - static int always_on = 0; - ImGui::RadioButton("Off", &always_on, 0); - ImGui::SameLine(); - ImGui::RadioButton("Always On (Simple)", &always_on, 1); - ImGui::SameLine(); - ImGui::RadioButton("Always On (Advanced)", &always_on, 2); - if (always_on == 1) - ImGui::SetTooltip("I am following you around."); - else if (always_on == 2 && ImGui::BeginTooltip()) - { - ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f)); - ImGui::EndTooltip(); - } - - ImGui::SeparatorText("Custom"); + // Tooltips + IMGUI_DEMO_MARKER("Widgets/Basic/Tooltips"); + ImGui::AlignTextToFramePadding(); + ImGui::Text("Tooltips:"); - // The following examples are passed for documentation purpose but may not be useful to most users. - // Passing ImGuiHoveredFlags_Tooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from - // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or gamepad/keyboard is being used. - // With default settings, ImGuiHoveredFlags_Tooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary. - ImGui::Button("Manual", sz); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) - ImGui::SetTooltip("I am a manually emitted tooltip"); + ImGui::SameLine(); + ImGui::Button("Button"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("I am a tooltip"); - ImGui::Button("DelayNone", sz); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone)) - ImGui::SetTooltip("I am a tooltip with no delay."); + ImGui::SameLine(); + ImGui::Button("Fancy"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("I am a fancy tooltip"); + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); + ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime())); + ImGui::EndTooltip(); + } - ImGui::Button("DelayShort", sz); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay)) - ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort); + ImGui::SameLine(); + ImGui::Button("Delayed"); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) // Delay best used on items that highlight on hover, so this not a great example! + ImGui::SetTooltip("I am a tooltip with a delay."); - ImGui::Button("DelayLong", sz); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay)) - ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec)", ImGui::GetStyle().HoverDelayNormal); + ImGui::SameLine(); + HelpMarker( + "Tooltip are created by using the IsItemHovered() function over any kind of item."); - ImGui::Button("Stationary", sz); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating."); + } ImGui::TreePop(); } @@ -1095,17 +1026,16 @@ static void ShowDemoWindowWidgets() float my_tex_w = (float)io.Fonts->TexWidth; float my_tex_h = (float)io.Fonts->TexHeight; { - static bool use_text_color_for_tint = false; - ImGui::Checkbox("Use Text Color for Tint", &use_text_color_for_tint); ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); ImVec2 pos = ImGui::GetCursorScreenPos(); ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right - ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint - ImVec4 border_col = ImGui::GetStyleColorVec4(ImGuiCol_Border); + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint + ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col); - if (ImGui::BeginItemTooltip()) + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); float region_sz = 32.0f; float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; @@ -1258,16 +1188,16 @@ static void ShowDemoWindowWidgets() IMGUI_DEMO_MARKER("Widgets/Selectables/Basic"); if (ImGui::TreeNode("Basic")) { - static bool selection[5] = { false, true, false, false }; + static bool selection[5] = { false, true, false, false, false }; ImGui::Selectable("1. I am selectable", &selection[0]); ImGui::Selectable("2. I am selectable", &selection[1]); - ImGui::Selectable("3. I am selectable", &selection[2]); - if (ImGui::Selectable("4. I am double clickable", selection[3], ImGuiSelectableFlags_AllowDoubleClick)) + ImGui::Text("(I am not selectable)"); + ImGui::Selectable("4. I am selectable", &selection[3]); + if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick)) if (ImGui::IsMouseDoubleClicked(0)) - selection[3] = !selection[3]; + selection[4] = !selection[4]; ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Selectables/Single Selection"); if (ImGui::TreeNode("Selection State: Single Selection")) { @@ -1299,18 +1229,17 @@ static void ShowDemoWindowWidgets() } ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line"); - if (ImGui::TreeNode("Rendering more items on the same line")) + IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more text into the same line"); + if (ImGui::TreeNode("Rendering more text into the same line")) { - // (1) Using SetNextItemAllowOverlap() - // (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. + // Using the Selectable() override that takes "bool* p_selected" parameter, + // this function toggle your bool value automatically. static bool selected[3] = { false, false, false }; - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1"); - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2"); - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3"); + ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); + ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes"); + ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Selectables/In columns"); if (ImGui::TreeNode("In columns")) { @@ -1346,7 +1275,6 @@ static void ShowDemoWindowWidgets() } ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Selectables/Grid"); if (ImGui::TreeNode("Grid")) { @@ -1442,15 +1370,7 @@ static void ShowDemoWindowWidgets() { struct TextFilters { - // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback) - static int FilterCasingSwap(ImGuiInputTextCallbackData* data) - { - if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase - else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase - return 0; - } - - // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out) + // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i' static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) { if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) @@ -1459,13 +1379,12 @@ static void ShowDemoWindowWidgets() } }; - static char buf1[32] = ""; ImGui::InputText("default", buf1, 32); - static char buf2[32] = ""; ImGui::InputText("decimal", buf2, 32, ImGuiInputTextFlags_CharsDecimal); - static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); - static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, 32, ImGuiInputTextFlags_CharsUppercase); - static char buf5[32] = ""; ImGui::InputText("no blank", buf5, 32, ImGuiInputTextFlags_CharsNoBlank); - static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters. - static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters. + static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); + static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal); + static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); + static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase); + static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); + static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); ImGui::TreePop(); } @@ -1480,7 +1399,6 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks"); if (ImGui::TreeNode("Completion, History, Edit Callbacks")) { struct Funcs @@ -1580,18 +1498,6 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous"); - if (ImGui::TreeNode("Miscellaneous")) - { - static char buf1[16]; - static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll; - ImGui::CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", &flags, ImGuiInputTextFlags_EscapeClearsAll); - ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); - ImGui::CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", &flags, ImGuiInputTextFlags_NoUndoRedo); - ImGui::InputText("Hello", buf1, IM_ARRAYSIZE(buf1), flags); - ImGui::TreePop(); - } - ImGui::TreePop(); } @@ -1783,7 +1689,7 @@ static void ShowDemoWindowWidgets() } // Use functions to generate output - // FIXME: This is actually VERY awkward because current plot API only pass in indices. + // FIXME: This is rather awkward because current plot API only pass in indices. // We probably want an API passing floats and user provide sample rate/count. struct Funcs { @@ -1791,7 +1697,7 @@ static void ShowDemoWindowWidgets() static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } }; static int func_type = 0, display_count = 70; - ImGui::SeparatorText("Functions"); + ImGui::Separator(); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::SameLine(); @@ -1834,7 +1740,6 @@ static void ShowDemoWindowWidgets() static bool drag_and_drop = true; static bool options_menu = true; static bool hdr = false; - ImGui::SeparatorText("Options"); ImGui::Checkbox("With Alpha Preview", &alpha_preview); ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); ImGui::Checkbox("With Drag and Drop", &drag_and_drop); @@ -1843,7 +1748,6 @@ static void ShowDemoWindowWidgets() ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit"); - ImGui::SeparatorText("Inline color editor"); ImGui::Text("Color widget:"); ImGui::SameLine(); HelpMarker( "Click on the color square to open a color picker.\n" @@ -1941,7 +1845,7 @@ static void ShowDemoWindowWidgets() ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); - ImGui::SeparatorText("Color picker"); + ImGui::Text("Color picker:"); static bool alpha = true; static bool alpha_bar = true; static bool side_preview = true; @@ -2112,7 +2016,7 @@ static void ShowDemoWindowWidgets() const float drag_speed = 0.2f; static bool drag_clamp = false; IMGUI_DEMO_MARKER("Widgets/Data Types/Drags"); - ImGui::SeparatorText("Drags"); + ImGui::Text("Drags:"); ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); ImGui::SameLine(); HelpMarker( "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" @@ -2132,7 +2036,7 @@ static void ShowDemoWindowWidgets() ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders"); - ImGui::SeparatorText("Sliders"); + ImGui::Text("Sliders"); ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); @@ -2157,7 +2061,7 @@ static void ShowDemoWindowWidgets() ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); - ImGui::SeparatorText("Sliders (reverse)"); + ImGui::Text("Sliders (reverse)"); ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); @@ -2167,7 +2071,7 @@ static void ShowDemoWindowWidgets() IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs"); static bool inputs_step = true; - ImGui::SeparatorText("Inputs"); + ImGui::Text("Inputs"); ImGui::Checkbox("Show step buttons", &inputs_step); ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d"); ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u"); @@ -2191,23 +2095,22 @@ static void ShowDemoWindowWidgets() static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; static int vec4i[4] = { 1, 5, 100, 255 }; - ImGui::SeparatorText("2-wide"); ImGui::InputFloat2("input float2", vec4f); ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); ImGui::InputInt2("input int2", vec4i); ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); ImGui::SliderInt2("slider int2", vec4i, 0, 255); + ImGui::Spacing(); - ImGui::SeparatorText("3-wide"); ImGui::InputFloat3("input float3", vec4f); ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); ImGui::InputInt3("input int3", vec4i); ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); ImGui::SliderInt3("slider int3", vec4i, 0, 255); + ImGui::Spacing(); - ImGui::SeparatorText("4-wide"); ImGui::InputFloat4("input float4", vec4f); ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); @@ -2440,10 +2343,8 @@ static void ShowDemoWindowWidgets() if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } bool hovered_delay_none = ImGui::IsItemHovered(); - bool hovered_delay_stationary = ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary); bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort); bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal); - bool hovered_delay_tooltip = ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip); // = Normal + Stationary // Display the values of IsItemHovered() and other common item state functions. // Note that the ImGuiHoveredFlags_XXX flags can be combined. @@ -2455,8 +2356,7 @@ static void ShowDemoWindowWidgets() "IsItemHovered() = %d\n" "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" - "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n" - "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n" + "IsItemHovered(_AllowWhenOverlapped) = %d\n" "IsItemHovered(_AllowWhenDisabled) = %d\n" "IsItemHovered(_RectOnly) = %d\n" "IsItemActive() = %d\n" @@ -2475,8 +2375,7 @@ static void ShowDemoWindowWidgets() ImGui::IsItemHovered(), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled), ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), ImGui::IsItemActive(), @@ -2492,13 +2391,7 @@ static void ShowDemoWindowWidgets() ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y ); ImGui::BulletText( - "with Hovering Delay or Stationary test:\n" - "IsItemHovered() = = %d\n" - "IsItemHovered(_Stationary) = %d\n" - "IsItemHovered(_DelayShort) = %d\n" - "IsItemHovered(_DelayNormal) = %d\n" - "IsItemHovered(_Tooltip) = %d", - hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip); + "w/ Hovering Delay: None = %d, Fast %d, Normal = %d", hovered_delay_none, hovered_delay_short, hovered_delay_normal); if (item_disabled) ImGui::EndDisabled(); @@ -2550,8 +2443,7 @@ static void ShowDemoWindowWidgets() "IsWindowHovered(_RootWindow) = %d\n" "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" - "IsWindowHovered(_AnyWindow) = %d\n" - "IsWindowHovered(_Stationary) = %d\n", + "IsWindowHovered(_AnyWindow) = %d\n", ImGui::IsWindowHovered(), ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), @@ -2562,8 +2454,7 @@ static void ShowDemoWindowWidgets() ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow), - ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary)); + ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); ImGui::BeginChild("child", ImVec2(0, 50), true); ImGui::Text("This is another child window for testing the _ChildWindows flag."); @@ -2636,8 +2527,6 @@ static void ShowDemoWindowLayout() IMGUI_DEMO_MARKER("Layout/Child windows"); if (ImGui::TreeNode("Child windows")) { - ImGui::SeparatorText("Child windows"); - HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); static bool disable_mouse_wheel = false; static bool disable_menu = false; @@ -2690,7 +2579,7 @@ static void ShowDemoWindowLayout() ImGui::PopStyleVar(); } - ImGui::SeparatorText("Misc/Advanced"); + ImGui::Separator(); // Demonstrate a few extra things // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) @@ -2806,11 +2695,11 @@ static void ShowDemoWindowLayout() // Text IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine"); ImGui::Text("Two items: Hello"); ImGui::SameLine(); - ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor"); + ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); // Adjust spacing ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); - ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor"); + ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); // Button ImGui::AlignTextToFramePadding(); @@ -2861,7 +2750,7 @@ static void ShowDemoWindowLayout() ImGui::PushID(i); ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items)); ImGui::PopID(); - //ImGui::SetItemTooltip("ListBox %d hovered", i); + //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); } ImGui::PopItemWidth(); @@ -2914,7 +2803,8 @@ static void ShowDemoWindowLayout() ImGui::SameLine(); ImGui::Button("EEE"); ImGui::EndGroup(); - ImGui::SetItemTooltip("First group hovered"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("First group hovered"); } // Capture the group size and create widgets using the same size ImVec2 size = ImGui::GetItemRectSize(); @@ -3408,36 +3298,6 @@ static void ShowDemoWindowLayout() ImGui::TreePop(); } - - IMGUI_DEMO_MARKER("Layout/Overlap Mode"); - if (ImGui::TreeNode("Overlap Mode")) - { - static bool enable_allow_overlap = true; - - HelpMarker( - "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n" - "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state."); - ImGui::Checkbox("Enable AllowOverlap", &enable_allow_overlap); - - ImVec2 button1_pos = ImGui::GetCursorScreenPos(); - ImVec2 button2_pos = ImVec2(button1_pos.x + 50.0f, button1_pos.y + 50.0f); - if (enable_allow_overlap) - ImGui::SetNextItemAllowOverlap(); - ImGui::Button("Button 1", ImVec2(80, 80)); - ImGui::SetCursorScreenPos(button2_pos); - ImGui::Button("Button 2", ImVec2(80, 80)); - - // This is typically used with width-spanning items. - // (note that Selectable() has a dedicated flag ImGuiSelectableFlags_AllowOverlap, which is a shortcut - // for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.) - if (enable_allow_overlap) - ImGui::SetNextItemAllowOverlap(); - ImGui::Selectable("Some Selectable", false); - ImGui::SameLine(); - ImGui::SmallButton("++"); - - ImGui::TreePop(); - } } static void ShowDemoWindowPopups() @@ -3483,7 +3343,8 @@ static void ShowDemoWindowPopups() ImGui::TextUnformatted(selected_fish == -1 ? "" : names[selected_fish]); if (ImGui::BeginPopup("my_select_popup")) { - ImGui::SeparatorText("Aquarium"); + ImGui::Text("Aquarium"); + ImGui::Separator(); for (int i = 0; i < IM_ARRAYSIZE(names); i++) if (ImGui::Selectable(names[i])) selected_fish = i; @@ -3505,7 +3366,8 @@ static void ShowDemoWindowPopups() ImGui::Separator(); ImGui::Text("Tooltip here"); - ImGui::SetItemTooltip("I am a tooltip over a popup"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("I am a tooltip over a popup"); if (ImGui::Button("Stacked Popup")) ImGui::OpenPopup("another popup"); @@ -3576,20 +3438,18 @@ static void ShowDemoWindowPopups() // and BeginPopupContextItem() will use the last item ID as the popup ID. { const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" }; - static int selected = -1; for (int n = 0; n < 5; n++) { - if (ImGui::Selectable(names[n], selected == n)) - selected = n; + ImGui::Selectable(names[n]); if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id { - selected = n; ImGui::Text("This a popup for \"%s\"!", names[n]); if (ImGui::Button("Close")) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } - ImGui::SetItemTooltip("Right-click to open popup"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Right-click to open popup"); } } @@ -3658,7 +3518,7 @@ static void ShowDemoWindowPopups() if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!"); + ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); ImGui::Separator(); //static int unused_i = 0; @@ -3841,8 +3701,9 @@ static void EditTableSizingFlags(ImGuiTableFlags* p_flags) } ImGui::SameLine(); ImGui::TextDisabled("(?)"); - if (ImGui::BeginItemTooltip()) + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f); for (int m = 0; m < IM_ARRAYSIZE(policies); m++) { @@ -5182,23 +5043,18 @@ static void ShowDemoWindowTables() if (ImGui::TreeNode("Synced instances")) { HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc."); - - static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings; - ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); - ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit); for (int n = 0; n < 3; n++) { char buf[32]; sprintf(buf, "Synced Table %d", n); bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen); - if (open && ImGui::BeginTable("Table", 3, flags, ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 5))) + if (open && ImGui::BeginTable("Table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings)) { ImGui::TableSetupColumn("One"); ImGui::TableSetupColumn("Two"); ImGui::TableSetupColumn("Three"); ImGui::TableHeadersRow(); - const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions. - for (int cell = 0; cell < cell_count; cell++) + for (int cell = 0; cell < 9; cell++) { ImGui::TableNextColumn(); ImGui::Text("this cell %d", cell); @@ -5539,7 +5395,7 @@ static void ShowDemoWindowTables() ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow) { - ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None; + ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap : ImGuiSelectableFlags_None; if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height))) { if (ImGui::GetIO().KeyCtrl) @@ -5826,93 +5682,50 @@ static void ShowDemoWindowColumns() ImGui::TreePop(); } +namespace ImGui { extern ImGuiKeyData* GetKeyData(ImGuiKey key); } + static void ShowDemoWindowInputs() { - IMGUI_DEMO_MARKER("Inputs & Focus"); - if (ImGui::CollapsingHeader("Inputs & Focus")) + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus"); + if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) { ImGuiIO& io = ImGui::GetIO(); - // Display inputs submitted to ImGuiIO - IMGUI_DEMO_MARKER("Inputs & Focus/Inputs"); - ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if (ImGui::TreeNode("Inputs")) - { - HelpMarker( - "This is a simplified view. See more detailed input state:\n" - "- in 'Tools->Metrics/Debugger->Inputs'.\n" - "- in 'Tools->Debug Log->IO'."); - if (ImGui::IsMousePosValid()) - ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); - else - ImGui::Text("Mouse pos: "); - ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); - ImGui::Text("Mouse down:"); - for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } - ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); - - // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends. - // User code should never have to go through such hoops! You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. -#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO - struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; - ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN; -#else - struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array - ImGuiKey start_key = (ImGuiKey)0; -#endif - ImGui::Text("Keys down:"); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); } - ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); - ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. - - ImGui::TreePop(); - } - // Display ImGuiIO output flags - IMGUI_DEMO_MARKER("Inputs & Focus/Outputs"); + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Output"); ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if (ImGui::TreeNode("Outputs")) + if (ImGui::TreeNode("Output")) { - HelpMarker( - "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui " - "to instruct your application of how to route inputs. Typically, when a value is true, it means " - "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n" - "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, " - "and underlying application should ignore mouse inputs (in practice there are many and more subtle " - "rules leading to how those flags are set)."); ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse); ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose); ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard); ImGui::Text("io.WantTextInput: %d", io.WantTextInput); ImGui::Text("io.WantSetMousePos: %d", io.WantSetMousePos); ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible); + ImGui::TreePop(); + } - IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override"); - if (ImGui::TreeNode("WantCapture override")) - { - HelpMarker( - "Hovering the colored canvas will override io.WantCaptureXXX fields.\n" - "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering and true when clicking."); - static int capture_override_mouse = -1; - static int capture_override_keyboard = -1; - const char* capture_override_desc[] = { "None", "Set to false", "Set to true" }; - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); - ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp); - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); - ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp); - - ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item - if (ImGui::IsItemHovered() && capture_override_mouse != -1) - ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1); - if (ImGui::IsItemHovered() && capture_override_keyboard != -1) - ImGui::SetNextFrameWantCaptureKeyboard(capture_override_keyboard == 1); + // Display Mouse state + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Mouse State"); + if (ImGui::TreeNode("Mouse State")) + { + if (ImGui::IsMousePosValid()) + ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); + else + ImGui::Text("Mouse pos: "); + ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); - ImGui::TreePop(); - } + int count = IM_ARRAYSIZE(io.MouseDown); + ImGui::Text("Mouse down:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } + ImGui::Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d (%d)", i, ImGui::GetMouseClickedCount(i)); } + ImGui::Text("Mouse released:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); + ImGui::Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused ImGui::TreePop(); } // Display mouse cursors - IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors"); + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Mouse Cursors"); if (ImGui::TreeNode("Mouse Cursors")) { const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" }; @@ -5940,7 +5753,113 @@ static void ShowDemoWindowInputs() ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing"); + // Display Keyboard/Mouse state + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Keyboard, Gamepad & Navigation State"); + if (ImGui::TreeNode("Keyboard, Gamepad & Navigation State")) + { + // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends. + // User code should never have to go through such hoops: old code may use native keycodes, new code may use ImGuiKey codes. +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; + const ImGuiKey key_first = (ImGuiKey)ImGuiKey_NamedKey_BEGIN; +#else + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array + const ImGuiKey key_first = (ImGuiKey)0; + //ImGui::Text("Legacy raw:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } } +#endif + ImGui::Text("Keys down:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key)) continue; if (ImGui::IsKeyDown(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d (%.02f)", ImGui::GetKeyName(key), key, ImGui::GetKeyData(key)->DownDuration); } } + ImGui::Text("Keys pressed:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key)) continue; if (ImGui::IsKeyPressed(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } } + ImGui::Text("Keys released:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key)) continue; if (ImGui::IsKeyReleased(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } } + ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); + ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. + + // Draw an arbitrary US keyboard layout to visualize translated keys + { + const ImVec2 key_size = ImVec2(35.0f, 35.0f); + const float key_rounding = 3.0f; + const ImVec2 key_face_size = ImVec2(25.0f, 25.0f); + const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f); + const float key_face_rounding = 2.0f; + const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f); + const ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f); + const float key_row_offset = 9.0f; + + ImVec2 board_min = ImGui::GetCursorScreenPos(); + ImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f); + ImVec2 start_pos = ImVec2(board_min.x + 5.0f - key_step.x, board_min.y); + + struct KeyLayoutData { int Row, Col; const char* Label; ImGuiKey Key; }; + const KeyLayoutData keys_to_display[] = + { + { 0, 0, "", ImGuiKey_Tab }, { 0, 1, "Q", ImGuiKey_Q }, { 0, 2, "W", ImGuiKey_W }, { 0, 3, "E", ImGuiKey_E }, { 0, 4, "R", ImGuiKey_R }, + { 1, 0, "", ImGuiKey_CapsLock }, { 1, 1, "A", ImGuiKey_A }, { 1, 2, "S", ImGuiKey_S }, { 1, 3, "D", ImGuiKey_D }, { 1, 4, "F", ImGuiKey_F }, + { 2, 0, "", ImGuiKey_LeftShift },{ 2, 1, "Z", ImGuiKey_Z }, { 2, 2, "X", ImGuiKey_X }, { 2, 3, "C", ImGuiKey_C }, { 2, 4, "V", ImGuiKey_V } + }; + + // Elements rendered manually via ImDrawList API are not clipped automatically. + // While not strictly necessary, here IsItemVisible() is used to avoid rendering these shapes when they are out of view. + ImGui::Dummy(ImVec2(board_max.x - board_min.x, board_max.y - board_min.y)); + if (ImGui::IsItemVisible()) + { + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + draw_list->PushClipRect(board_min, board_max, true); + for (int n = 0; n < IM_ARRAYSIZE(keys_to_display); n++) + { + const KeyLayoutData* key_data = &keys_to_display[n]; + ImVec2 key_min = ImVec2(start_pos.x + key_data->Col * key_step.x + key_data->Row * key_row_offset, start_pos.y + key_data->Row * key_step.y); + ImVec2 key_max = ImVec2(key_min.x + key_size.x, key_min.y + key_size.y); + draw_list->AddRectFilled(key_min, key_max, IM_COL32(204, 204, 204, 255), key_rounding); + draw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding); + ImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y); + ImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y); + draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f); + draw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding); + ImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y); + draw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label); + if (ImGui::IsKeyDown(key_data->Key)) + draw_list->AddRectFilled(key_min, key_max, IM_COL32(255, 0, 0, 128), key_rounding); + } + draw_list->PopClipRect(); + } + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Capture override")) + { + HelpMarker( + "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui " + "to instruct your application of how to route inputs. Typically, when a value is true, it means " + "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n" + "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, " + "and underlying application should ignore mouse inputs (in practice there are many and more subtle " + "rules leading to how those flags are set)."); + + ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse); + ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose); + ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard); + + HelpMarker( + "Hovering the colored canvas will override io.WantCaptureXXX fields.\n" + "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering and true when clicking."); + static int capture_override_mouse = -1; + static int capture_override_keyboard = -1; + const char* capture_override_desc[] = { "None", "Set to false", "Set to true" }; + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); + ImGui::SliderInt("SetNextFrameWantCaptureMouse()", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); + ImGui::SliderInt("SetNextFrameWantCaptureKeyboard()", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp); + + ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(256.0f, 192.0f)); // Dummy item + if (ImGui::IsItemHovered() && capture_override_mouse != -1) + ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1); + if (ImGui::IsItemHovered() && capture_override_keyboard != -1) + ImGui::SetNextFrameWantCaptureKeyboard(capture_override_keyboard == 1); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Tabbing"); if (ImGui::TreeNode("Tabbing")) { ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); @@ -5948,15 +5867,15 @@ static void ShowDemoWindowInputs() ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); - ImGui::PushTabStop(false); + ImGui::PushAllowKeyboardFocus(false); ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); - ImGui::PopTabStop(); + ImGui::PopAllowKeyboardFocus(); ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code"); + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Focus from code"); if (ImGui::TreeNode("Focus from code")) { bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); @@ -5973,12 +5892,12 @@ static void ShowDemoWindowInputs() ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); if (ImGui::IsItemActive()) has_focus = 2; - ImGui::PushTabStop(false); + ImGui::PushAllowKeyboardFocus(false); if (focus_3) ImGui::SetKeyboardFocusHere(); ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); if (ImGui::IsItemActive()) has_focus = 3; ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); - ImGui::PopTabStop(); + ImGui::PopAllowKeyboardFocus(); if (has_focus) ImGui::Text("Item with focus: %d", has_focus); @@ -5998,7 +5917,7 @@ static void ShowDemoWindowInputs() ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Inputs & Focus/Dragging"); + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Dragging"); if (ImGui::TreeNode("Dragging")) { ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); @@ -6042,11 +5961,10 @@ void ImGui::ShowAboutWindow(bool* p_open) return; } IMGUI_DEMO_MARKER("Tools/About Dear ImGui"); - ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); + ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); ImGui::Separator(); ImGui::Text("By Omar Cornut and all Dear ImGui contributors."); ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); - ImGui::Text("If your company uses this, please consider sponsoring the project!"); static bool show_config_info = false; ImGui::Checkbox("Config/Build Information", &show_config_info); @@ -6130,9 +6048,6 @@ void ImGui::ShowAboutWindow(bool* p_open) #endif #ifdef __clang_version__ ImGui::Text("define: __clang_version__=%s", __clang_version__); -#endif -#ifdef __EMSCRIPTEN__ - ImGui::Text("define: __EMSCRIPTEN__"); #endif ImGui::Separator(); ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); @@ -6282,7 +6197,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { if (ImGui::BeginTabItem("Sizes")) { - ImGui::SeparatorText("Main"); + ImGui::Text("Main"); ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f"); @@ -6292,24 +6207,22 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); - - ImGui::SeparatorText("Borders"); + ImGui::Text("Borders"); ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); - - ImGui::SeparatorText("Rounding"); + ImGui::Text("Rounding"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); - - ImGui::SeparatorText("Widgets"); + ImGui::Text("Alignment"); ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); int window_menu_button_position = style.WindowMenuButtonPosition + 1; if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) @@ -6319,27 +6232,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); - ImGui::SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f"); - ImGui::SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); - ImGui::SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f"); - ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); - - ImGui::SeparatorText("Tooltips"); - for (int n = 0; n < 2; n++) - if (ImGui::TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav")) - { - ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav; - ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone); - ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayShort", p, ImGuiHoveredFlags_DelayShort); - ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p, ImGuiHoveredFlags_DelayNormal); - ImGui::CheckboxFlags("ImGuiHoveredFlags_Stationary", p, ImGuiHoveredFlags_Stationary); - ImGui::CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", p, ImGuiHoveredFlags_NoSharedDelay); - ImGui::TreePop(); - } - - ImGui::SeparatorText("Misc"); - ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); - + ImGui::Text("Safe Area Padding"); + ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); + ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::EndTabItem(); } @@ -6449,11 +6344,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); - const bool show_samples = ImGui::IsItemActive(); - if (show_samples) - ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos()); - if (show_samples && ImGui::BeginTooltip()) + if (ImGui::IsItemActive()) { + ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos()); + ImGui::BeginTooltip(); ImGui::TextUnformatted("(R = radius, N = number of segments)"); ImGui::Spacing(); ImDrawList* draw_list = ImGui::GetWindowDrawList(); @@ -6650,7 +6544,6 @@ static void ShowExampleMenuFile() IM_ASSERT(0); } if (ImGui::MenuItem("Checked", NULL, true)) {} - ImGui::Separator(); if (ImGui::MenuItem("Quit", "Alt+F4")) {} } @@ -7194,7 +7087,7 @@ static void ShowExampleAppLayout(bool* p_open) { if (ImGui::BeginMenu("File")) { - if (ImGui::MenuItem("Close", "Ctrl+W")) { *p_open = false; } + if (ImGui::MenuItem("Close")) *p_open = false; ImGui::EndMenu(); } ImGui::EndMenuBar(); @@ -7569,7 +7462,7 @@ static void ShowExampleAppFullscreen(bool* p_open) static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings; // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.) - // Based on your use case you may want one or the other. + // Based on your use case you may want one of the other. const ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos); ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size); @@ -8121,8 +8014,8 @@ void ShowExampleAppDocuments(bool* p_open) for (int n = 0; n < close_queue.Size; n++) if (close_queue[n]->Dirty) ImGui::Text("%s", close_queue[n]->Name); + ImGui::EndChildFrame(); } - ImGui::EndChildFrame(); ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f); if (ImGui::Button("Yes", button_size)) diff --git a/3rdparty/bgfx/3rdparty/dear-imgui/imgui_draw.cpp b/3rdparty/bgfx/3rdparty/dear-imgui/imgui_draw.cpp index d3a332a1774..859b62e7e97 100644 --- a/3rdparty/bgfx/3rdparty/dear-imgui/imgui_draw.cpp +++ b/3rdparty/bgfx/3rdparty/dear-imgui/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.8 WIP +// dear imgui, v1.89.1 WIP // (drawing and font code) /* @@ -26,12 +26,13 @@ Index of this file: #define _CRT_SECURE_NO_WARNINGS #endif +#include "imgui.h" +#ifndef IMGUI_DISABLE + #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif -#include "imgui.h" -#ifndef IMGUI_DISABLE #include "imgui_internal.h" #ifdef IMGUI_ENABLE_FREETYPE #include "misc/freetype/imgui_freetype.h" @@ -63,7 +64,6 @@ Index of this file: #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision -#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used @@ -389,8 +389,6 @@ void ImDrawList::_ResetForNewFrame() IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0); IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4)); IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID)); - if (_Splitter._Count > 1) - _Splitter.Merge(this); CmdBuffer.resize(0); IdxBuffer.resize(0); @@ -449,13 +447,11 @@ void ImDrawList::AddDrawCmd() // Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL void ImDrawList::_PopUnusedDrawCmd() { - while (CmdBuffer.Size > 0) - { - ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL) - return;// break; + if (CmdBuffer.Size == 0) + return; + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL) CmdBuffer.pop_back(); - } } void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) @@ -708,7 +704,7 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c // We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness) { - if (points_count < 2 || (col & IM_COL32_A_MASK) == 0) + if (points_count < 2) return; const bool closed = (flags & ImDrawFlags_Closed) != 0; @@ -966,7 +962,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 // - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) { - if (points_count < 3 || (col & IM_COL32_A_MASK) == 0) + if (points_count < 3) return; const ImVec2 uv = _Data->TexUvWhitePixel; @@ -1809,63 +1805,6 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) // [SECTION] ImDrawData //----------------------------------------------------------------------------- -void ImDrawData::Clear() -{ - Valid = false; - CmdListsCount = TotalIdxCount = TotalVtxCount = 0; - CmdLists.resize(0); // The ImDrawList are NOT owned by ImDrawData but e.g. by ImGuiContext, so we don't clear them. - DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.0f, 0.0f); - OwnerViewport = NULL; -} - -// Important: 'out_list' is generally going to be draw_data->CmdLists, but may be another temporary list -// as long at it is expected that the result will be later merged into draw_data->CmdLists[]. -void ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector* out_list, ImDrawList* draw_list) -{ - if (draw_list->CmdBuffer.Size == 0) - return; - if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && draw_list->CmdBuffer[0].UserCallback == NULL) - return; - - // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. - // May trigger for you if you are using PrimXXX functions incorrectly. - IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); - IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); - if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset)) - IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); - - // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) - // If this assert triggers because you are drawing lots of stuff manually: - // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds. - // Be mindful that the lower-level ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents. - // - If you want large meshes with more than 64K vertices, you can either: - // (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'. - // Most example backends already support this from 1.71. Pre-1.71 backends won't. - // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them. - // (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h. - // Most example backends already support this. For example, the OpenGL example code detect index size at compile-time: - // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); - // Your own engine or render API may use different parameters or function calls to specify index sizes. - // 2 and 4 bytes indices are generally supported by most graphics API. - // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching - // the 64K limit to split your draw commands in multiple draw lists. - if (sizeof(ImDrawIdx) == 2) - IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); - - // Add to output list + records state in ImDrawData - out_list->push_back(draw_list); - draw_data->CmdListsCount++; - draw_data->TotalVtxCount += draw_list->VtxBuffer.Size; - draw_data->TotalIdxCount += draw_list->IdxBuffer.Size; -} - -void ImDrawData::AddDrawList(ImDrawList* draw_list) -{ - IM_ASSERT(CmdLists.Size == CmdListsCount); - draw_list->_PopUnusedDrawCmd(); - ImGui::AddDrawListToDrawDataEx(this, &CmdLists, draw_list); -} - // For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! void ImDrawData::DeIndexAllBuffers() { @@ -1962,7 +1901,7 @@ ImFontConfig::ImFontConfig() { memset(this, 0, sizeof(*this)); FontDataOwnedByAtlas = true; - OversampleH = 2; + OversampleH = 3; // FIXME: 2 may be a better default? OversampleV = 1; GlyphMaxAdvanceX = FLT_MAX; RasterizerMultiply = 1.0f; @@ -2441,12 +2380,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) - { - // Check for valid range. This may also help detect *some* dangling pointers, because a common - // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent. - IM_ASSERT(src_range[0] <= src_range[1]); src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); - } dst_tmp.SrcCount++; dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); } @@ -2611,10 +2545,13 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) // 9. Setup ImFont and glyphs for runtime for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + // When merging fonts with MergeMode=true: // - We can have multiple input fonts writing into a same destination font. // - dst_font->ConfigData is != from cfg which is our source configuration. - ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; ImFontConfig& cfg = atlas->ConfigData[src_i]; ImFont* dst_font = cfg.DstFont; @@ -2678,9 +2615,6 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa ImVector& user_rects = atlas->CustomRects; IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. -#ifdef __GNUC__ - if (user_rects.Size < 1) { __builtin_unreachable(); } // Workaround for GCC bug if IM_ASSERT() is defined to conditionally throw (see #5343) -#endif ImVector pack_rects; pack_rects.resize(user_rects.Size); @@ -3001,19 +2935,19 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() // 2999 ideograms code points for Japanese // - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points // - 863 Jinmeiyo (meaning "for personal name") Kanji code points - // - Sourced from official information provided by the government agencies of Japan: - // - List of Joyo Kanji by the Agency for Cultural Affairs - // - https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/ - // - List of Jinmeiyo Kanji by the Ministry of Justice - // - http://www.moj.go.jp/MINJI/minji86.html - // - Available under the terms of the Creative Commons Attribution 4.0 International (CC BY 4.0). - // - https://creativecommons.org/licenses/by/4.0/legalcode - // - You can generate this code by the script at: - // - https://github.com/vaiorabbit/everyday_use_kanji + // - Sourced from the character information database of the Information-technology Promotion Agency, Japan + // - https://mojikiban.ipa.go.jp/mji/ + // - Available under the terms of the Creative Commons Attribution-ShareAlike 2.1 Japan (CC BY-SA 2.1 JP). + // - https://creativecommons.org/licenses/by-sa/2.1/jp/deed.en + // - https://creativecommons.org/licenses/by-sa/2.1/jp/legalcode + // - You can generate this code by the script at: + // - https://github.com/vaiorabbit/everyday_use_kanji // - References: // - List of Joyo Kanji + // - (Official list by the Agency for Cultural Affairs) https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kakuki/14/tosin02/index.html // - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji // - List of Jinmeiyo Kanji + // - (Official list by the Ministry of Justice) http://www.moj.go.jp/MINJI/minji86.html // - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji // - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details. // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. @@ -3176,8 +3110,7 @@ ImFont::ImFont() FallbackAdvanceX = 0.0f; FallbackChar = (ImWchar)-1; EllipsisChar = (ImWchar)-1; - EllipsisWidth = EllipsisCharStep = 0.0f; - EllipsisCharCount = 0; + DotChar = (ImWchar)-1; FallbackGlyph = NULL; ContainerAtlas = NULL; ConfigData = NULL; @@ -3258,7 +3191,17 @@ void ImFont::BuildLookupTable() SetGlyphVisible((ImWchar)' ', false); SetGlyphVisible((ImWchar)'\t', false); - // Setup Fallback character + // Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). + // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. + // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. + const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 }; + const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; + if (EllipsisChar == (ImWchar)-1) + EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars)); + if (DotChar == (ImWchar)-1) + DotChar = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars)); + + // Setup fallback character const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; FallbackGlyph = FindGlyphNoFallback(FallbackChar); if (FallbackGlyph == NULL) @@ -3271,32 +3214,11 @@ void ImFont::BuildLookupTable() FallbackChar = (ImWchar)FallbackGlyph->Codepoint; } } + FallbackAdvanceX = FallbackGlyph->AdvanceX; for (int i = 0; i < max_codepoint + 1; i++) if (IndexAdvanceX[i] < 0.0f) IndexAdvanceX[i] = FallbackAdvanceX; - - // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). - // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. - // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. - const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 }; - const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; - if (EllipsisChar == (ImWchar)-1) - EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars)); - const ImWchar dot_char = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars)); - if (EllipsisChar != (ImWchar)-1) - { - EllipsisCharCount = 1; - EllipsisWidth = EllipsisCharStep = FindGlyph(EllipsisChar)->X1; - } - else if (dot_char != (ImWchar)-1) - { - const ImFontGlyph* glyph = FindGlyph(dot_char); - EllipsisChar = dot_char; - EllipsisCharCount = 3; - EllipsisCharStep = (glyph->X1 - glyph->X0) + 1.0f; - EllipsisWidth = EllipsisCharStep * 3.0f - 1.0f; - } } // API is designed this way to avoid exposing the 4K page size @@ -3445,7 +3367,6 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c bool inside_word = true; const char* s = text; - IM_ASSERT(text_end != NULL); while (s < text_end) { unsigned int c = (unsigned int)*s; @@ -3454,6 +3375,8 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c next_s = s + 1; else next_s = s + ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) + break; if (c < 32) { @@ -3559,9 +3482,15 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons const char* prev_s = s; unsigned int c = (unsigned int)*s; if (c < 0x80) + { s += 1; + } else + { s += ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) // Malformed UTF-8? + break; + } if (c < 32) { @@ -3641,7 +3570,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA(). // If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both. // However it is still better than nothing performing the fast-forward! - s = CalcWordWrapPositionA(scale, s, line_end ? line_end : text_end, wrap_width); + s = CalcWordWrapPositionA(scale, s, line_end, wrap_width); s = CalcWordWrapNextLineStartA(s, text_end); } else @@ -3673,9 +3602,10 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im const int idx_count_max = (int)(text_end - s) * 6; const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; draw_list->PrimReserve(idx_count_max, vtx_count_max); - ImDrawVert* vtx_write = draw_list->_VtxWritePtr; - ImDrawIdx* idx_write = draw_list->_IdxWritePtr; - unsigned int vtx_index = draw_list->_VtxCurrentIdx; + + ImDrawVert* vtx_write = draw_list->_VtxWritePtr; + ImDrawIdx* idx_write = draw_list->_IdxWritePtr; + unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; const ImU32 col_untinted = col | ~IM_COL32_A_MASK; const char* word_wrap_eol = NULL; @@ -3701,9 +3631,15 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im // Decode and advance source unsigned int c = (unsigned int)*s; if (c < 0x80) + { s += 1; + } else + { s += ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) // Malformed UTF-8? + break; + } if (c < 32) { @@ -3774,14 +3710,14 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: { + idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2); + idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3); vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; - idx_write[0] = (ImDrawIdx)(vtx_index); idx_write[1] = (ImDrawIdx)(vtx_index + 1); idx_write[2] = (ImDrawIdx)(vtx_index + 2); - idx_write[3] = (ImDrawIdx)(vtx_index); idx_write[4] = (ImDrawIdx)(vtx_index + 2); idx_write[5] = (ImDrawIdx)(vtx_index + 3); vtx_write += 4; - vtx_index += 4; + vtx_current_idx += 4; idx_write += 6; } } @@ -3795,7 +3731,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); draw_list->_VtxWritePtr = vtx_write; draw_list->_IdxWritePtr = idx_write; - draw_list->_VtxCurrentIdx = vtx_index; + draw_list->_VtxCurrentIdx = vtx_current_idx; } //----------------------------------------------------------------------------- @@ -3847,7 +3783,6 @@ void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir d void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col) { - // FIXME-OPT: This should be baked in font. draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8); } diff --git a/3rdparty/bgfx/3rdparty/dear-imgui/imgui_internal.h b/3rdparty/bgfx/3rdparty/dear-imgui/imgui_internal.h index 1d782dc6219..015f6b65756 100644 --- a/3rdparty/bgfx/3rdparty/dear-imgui/imgui_internal.h +++ b/3rdparty/bgfx/3rdparty/dear-imgui/imgui_internal.h @@ -1,12 +1,10 @@ -// dear imgui, v1.89.8 WIP +// dear imgui, v1.89.1 WIP // (internal structures/api) -// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. -// To implement maths operators for ImVec2 (disabled by default to not conflict with using IM_VEC2_CLASS_EXTRA with your own math types+operators), use: -/* -#define IMGUI_DEFINE_MATH_OPERATORS -#include "imgui_internal.h" -*/ +// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! +// Set: +// #define IMGUI_DEFINE_MATH_OPERATORS +// To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators) /* @@ -58,7 +56,7 @@ Index of this file: #include // INT_MIN, INT_MAX // Enable SSE intrinsics if available -#if (defined __SSE__ || defined __x86_64__ || defined _M_X64 || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))) && !defined(IMGUI_DISABLE_SSE) +#if (defined __SSE__ || defined __x86_64__ || defined _M_X64) && !defined(IMGUI_DISABLE_SSE) #define IMGUI_ENABLE_SSE #include #endif @@ -95,12 +93,6 @@ Index of this file: #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif -// In 1.89.4, we moved the implementation of "courtesy maths operators" from imgui_internal.h in imgui.h -// As they are frequently requested, we do not want to encourage to many people using imgui_internal.h -#if defined(IMGUI_DEFINE_MATH_OPERATORS) && !defined(IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED) -#error Please '#define IMGUI_DEFINE_MATH_OPERATORS' _BEFORE_ including imgui.h! -#endif - // Legacy defines #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74 #error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS @@ -126,11 +118,9 @@ struct ImDrawListSharedData; // Data shared between all ImDrawList instan struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it struct ImGuiContext; // Main Dear ImGui context struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine -struct ImGuiDataVarInfo; // Variable information (e.g. to avoid style variables from an enum) struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup() struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box -struct ImGuiInputTextDeactivateData;// Short term storage to backup text of a deactivating InputText() while another is stealing active id struct ImGuiLastItemData; // Status storage for last submitted items struct ImGuiLocEntry; // A localization entry. struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only @@ -164,7 +154,6 @@ typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // E // Flags typedef int ImGuiActivateFlags; // -> enum ImGuiActivateFlags_ // Flags: for navigation/focus function (will be for ActivateItem() later) typedef int ImGuiDebugLogFlags; // -> enum ImGuiDebugLogFlags_ // Flags: for ShowDebugLogWindow(), g.DebugLogFlags -typedef int ImGuiFocusRequestFlags; // -> enum ImGuiFocusRequestFlags_ // Flags: for FocusWindow(); typedef int ImGuiInputFlags; // -> enum ImGuiInputFlags_ // Flags: for IsKeyPressed(), IsMouseClicked(), SetKeyOwner(), SetItemKeyOwner() etc. typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag(), g.LastItemData.InFlags typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for g.LastItemData.StatusFlags @@ -217,21 +206,16 @@ namespace ImStb #ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS #define IMGUI_DEBUG_PRINTF(_FMT,...) printf(_FMT, __VA_ARGS__) #else -#define IMGUI_DEBUG_PRINTF(_FMT,...) ((void)0) +#define IMGUI_DEBUG_PRINTF(_FMT,...) #endif #endif // Debug Logging for ShowDebugLogWindow(). This is designed for relatively rare events so please don't spam. -#ifndef IMGUI_DISABLE_DEBUG_TOOLS #define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__) -#else -#define IMGUI_DEBUG_LOG(...) ((void)0) -#endif #define IMGUI_DEBUG_LOG_ACTIVEID(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventActiveId) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_FOCUS(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_NAV(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventNav) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) -#define IMGUI_DEBUG_LOG_SELECTION(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection)IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_CLIPPER(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_IO(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) @@ -268,8 +252,6 @@ namespace ImStb #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 #define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds #define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) // -#define IM_STRINGIFY_HELPER(_X) #_X -#define IM_STRINGIFY(_X) IM_STRINGIFY_HELPER(_X) // Preprocessor idiom to stringify e.g. an integer. // Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall #ifdef _MSC_VER @@ -330,8 +312,8 @@ namespace ImStb //----------------------------------------------------------------------------- // Helpers: Hashing -IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImGuiID seed = 0); -IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImGuiID seed = 0); +IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImU32 seed = 0); +IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0); // Helpers: Sorting #ifndef ImQsort @@ -386,6 +368,29 @@ IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8 IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 +// Helpers: ImVec2/ImVec4 operators +// We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.) +// We unfortunately don't have a unary- operator for ImVec2 because this would needs to be defined inside the class itself. +#ifdef IMGUI_DEFINE_MATH_OPERATORS +IM_MSVC_RUNTIME_CHECKS_OFF +static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } +static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } +static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } +static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } +static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } +static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } +static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } +static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } +static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } +static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } +static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } +static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } +IM_MSVC_RUNTIME_CHECKS_RESTORE +#endif + // Helpers: File System #ifdef IMGUI_DISABLE_FILE_FUNCTIONS #define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS @@ -468,7 +473,6 @@ static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } static inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; } -static inline float ImExponentialMovingAverage(float avg, float sample, int n) { avg -= avg / n; avg += sample / n; return avg; } IM_MSVC_RUNTIME_CHECKS_RESTORE // Helpers: Geometry @@ -481,6 +485,7 @@ IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, c IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); inline float ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; } +IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy); // Helper: ImVec1 (1D vector) // (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) @@ -538,12 +543,9 @@ struct IMGUI_API ImRect bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); } }; +IM_MSVC_RUNTIME_CHECKS_RESTORE // Helper: ImBitArray -#define IM_BITARRAY_TESTBIT(_ARRAY, _N) ((_ARRAY[(_N) >> 5] & ((ImU32)1 << ((_N) & 31))) != 0) // Macro version of ImBitArrayTestBit(): ensure args have side-effect or are costly! -#define IM_BITARRAY_CLEARBIT(_ARRAY, _N) ((_ARRAY[(_N) >> 5] &= ~((ImU32)1 << ((_N) & 31)))) // Macro version of ImBitArrayClearBit(): ensure args have side-effect or are costly! -inline size_t ImBitArrayGetStorageSizeInBytes(int bitcount) { return (size_t)((bitcount + 31) >> 5) << 2; } -inline void ImBitArrayClearAllBits(ImU32* arr, int bitcount){ memset(arr, 0, ImBitArrayGetStorageSizeInBytes(bitcount)); } inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; } inline void ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; } inline void ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; } @@ -560,8 +562,6 @@ inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) // Works on ran } } -typedef ImU32* ImBitArrayPtr; // Name for use in structs - // Helper: ImBitArray class (wrapper over ImBitArray functions) // Store 1-bit per value. template @@ -571,11 +571,11 @@ struct ImBitArray ImBitArray() { ClearAllBits(); } void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); } void SetAllBits() { memset(Storage, 255, sizeof(Storage)); } - bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); } + bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } void SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); } void ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); } void SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2) - bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); } + bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } }; // Helper: ImBitVector @@ -585,11 +585,10 @@ struct IMGUI_API ImBitVector ImVector Storage; void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } void Clear() { Storage.clear(); } - bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return IM_BITARRAY_TESTBIT(Storage.Data, n); } + bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return ImBitArrayTestBit(Storage.Data, n); } void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); } void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); } }; -IM_MSVC_RUNTIME_CHECKS_RESTORE // Helper: ImSpan<> // Pointing to a span of data we don't own. @@ -772,10 +771,12 @@ struct IMGUI_API ImDrawListSharedData struct ImDrawDataBuilder { - ImVector* Layers[2]; // Pointers to global layers for: regular, tooltip. LayersP[0] is owned by DrawData. - ImVector LayerData1; + ImVector Layers[2]; // Global layers for: regular, tooltip - ImDrawDataBuilder() { memset(this, 0, sizeof(*this)); } + void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } + void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } + int GetDrawListCount() const { int count = 0; for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) count += Layers[n].Size; return count; } + IMGUI_API void FlattenIntoSingleLayer(); }; //----------------------------------------------------------------------------- @@ -791,16 +792,15 @@ enum ImGuiItemFlags_ { // Controlled by user ImGuiItemFlags_None = 0, - ImGuiItemFlags_NoTabStop = 1 << 0, // false // Disable keyboard tabbing. This is a "lighter" version of ImGuiItemFlags_NoNav. + ImGuiItemFlags_NoTabStop = 1 << 0, // false // Disable keyboard tabbing (FIXME: should merge with _NoNav) ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. ImGuiItemFlags_Disabled = 1 << 2, // false // Disable interactions but doesn't affect visuals. See BeginDisabled()/EndDisabled(). See github.com/ocornut/imgui/issues/211 - ImGuiItemFlags_NoNav = 1 << 3, // false // Disable any form of focusing (keyboard/gamepad directional navigation and SetKeyboardFocusHere() calls) + ImGuiItemFlags_NoNav = 1 << 3, // false // Disable keyboard/gamepad directional navigation (FIXME: should merge with _NoTabStop) ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false // Disable item being a candidate for default focus (e.g. used by title bar items) ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // Disable MenuItem/Selectable() automatically closing their popup window ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. ImGuiItemFlags_NoWindowHoverableCheck = 1 << 8, // false // Disable hoverable check in ItemHoverable() - ImGuiItemflags_AllowOverlap = 1 << 9, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame. // Controlled by widget code ImGuiItemFlags_Inputable = 1 << 10, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. @@ -822,24 +822,14 @@ enum ImGuiItemStatusFlags_ ImGuiItemStatusFlags_FocusedByTabbing = 1 << 8, // Set when the Focusable item just got focused by Tabbing (FIXME: to be removed soon) ImGuiItemStatusFlags_Visible = 1 << 9, // [WIP] Set when item is overlapping the current clipping rectangle (Used internally. Please don't use yet: API/system will change as we refactor Itemadd()). - // Additional status + semantic for ImGuiTestEngine #ifdef IMGUI_ENABLE_TEST_ENGINE ImGuiItemStatusFlags_Openable = 1 << 20, // Item is an openable (e.g. TreeNode) - ImGuiItemStatusFlags_Opened = 1 << 21, // Opened status + ImGuiItemStatusFlags_Opened = 1 << 21, // ImGuiItemStatusFlags_Checkable = 1 << 22, // Item is a checkable (e.g. CheckBox, MenuItem) - ImGuiItemStatusFlags_Checked = 1 << 23, // Checked status - ImGuiItemStatusFlags_Inputable = 1 << 24, // Item is a text-inputable (e.g. InputText, SliderXXX, DragXXX) + ImGuiItemStatusFlags_Checked = 1 << 23, // #endif }; -// Extend ImGuiHoveredFlags_ -enum ImGuiHoveredFlagsPrivate_ -{ - ImGuiHoveredFlags_DelayMask_ = ImGuiHoveredFlags_DelayNone | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay, - ImGuiHoveredFlags_AllowedMaskForIsWindowHovered = ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary, - ImGuiHoveredFlags_AllowedMaskForIsItemHovered = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayMask_, -}; - // Extend ImGuiInputTextFlags_ enum ImGuiInputTextFlagsPrivate_ { @@ -860,7 +850,7 @@ enum ImGuiButtonFlagsPrivate_ ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping - ImGuiButtonFlags_AllowOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable. + ImGuiButtonFlags_AllowItemOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press // [UNUSED] //ImGuiButtonFlags_Disabled = 1 << 14, // disable interactions -> use BeginDisabled() or ImGuiItemFlags_Disabled ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine @@ -896,16 +886,16 @@ enum ImGuiSelectableFlagsPrivate_ ImGuiSelectableFlags_SelectOnClick = 1 << 22, // Override button behavior to react on Click (default is Click+Release) ImGuiSelectableFlags_SelectOnRelease = 1 << 23, // Override button behavior to react on Release (default is Click+Release) ImGuiSelectableFlags_SpanAvailWidth = 1 << 24, // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus) - ImGuiSelectableFlags_SetNavIdOnHover = 1 << 25, // Set Nav/Focus ID on mouse hover (used by MenuItem) - ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 26, // Disable padding each side with ItemSpacing * 0.5f - ImGuiSelectableFlags_NoSetKeyOwner = 1 << 27, // Don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) + ImGuiSelectableFlags_DrawHoveredWhenHeld = 1 << 25, // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow. + ImGuiSelectableFlags_SetNavIdOnHover = 1 << 26, // Set Nav/Focus ID on mouse hover (used by MenuItem) + ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 27, // Disable padding each side with ItemSpacing * 0.5f + ImGuiSelectableFlags_NoSetKeyOwner = 1 << 28, // Don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) }; // Extend ImGuiTreeNodeFlags_ enum ImGuiTreeNodeFlagsPrivate_ { ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20, - ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 21,// (FIXME-WIP) Turn Down arrow into an Up arrow, but reversed trees (#6517) }; enum ImGuiSeparatorFlags_ @@ -913,17 +903,7 @@ enum ImGuiSeparatorFlags_ ImGuiSeparatorFlags_None = 0, ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar ImGuiSeparatorFlags_Vertical = 1 << 1, - ImGuiSeparatorFlags_SpanAllColumns = 1 << 2, // Make separator cover all columns of a legacy Columns() set. -}; - -// Flags for FocusWindow(). This is not called ImGuiFocusFlags to avoid confusion with public-facing ImGuiFocusedFlags. -// FIXME: Once we finishing replacing more uses of GetTopMostPopupModal()+IsWindowWithinBeginStackOf() -// and FindBlockingModal() with this, we may want to change the flag to be opt-out instead of opt-in. -enum ImGuiFocusRequestFlags_ -{ - ImGuiFocusRequestFlags_None = 0, - ImGuiFocusRequestFlags_RestoreFocusedChild = 1 << 0, // Find last focused child (if any) and focus it instead. - ImGuiFocusRequestFlags_UnlessBelowModal = 1 << 1, // Do not set focus if the window is below a modal. + ImGuiSeparatorFlags_SpanAllColumns = 1 << 2, }; enum ImGuiTextFlags_ @@ -935,7 +915,7 @@ enum ImGuiTextFlags_ enum ImGuiTooltipFlags_ { ImGuiTooltipFlags_None = 0, - ImGuiTooltipFlags_OverridePrevious = 1 << 1, // Clear/ignore previously submitted tooltip (defaults to append) + ImGuiTooltipFlags_OverridePreviousTooltip = 1 << 0, // Override will clear/ignore previously submitted tooltip (defaults to append) }; // FIXME: this is in development, not exposed/functional as a generic feature yet. @@ -976,14 +956,6 @@ enum ImGuiPopupPositionPolicy ImGuiPopupPositionPolicy_Tooltip, }; -struct ImGuiDataVarInfo -{ - ImGuiDataType Type; - ImU32 Count; // 1+ - ImU32 Offset; // Offset in parent structure - void* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); } -}; - struct ImGuiDataTypeTempStorage { ImU8 Data[8]; // Can fit any data up to ImGuiDataType_COUNT @@ -1070,20 +1042,10 @@ struct IMGUI_API ImGuiMenuColumns void CalcNextTotalWidth(bool update_offsets); }; -// Internal temporary state for deactivating InputText() instances. -struct IMGUI_API ImGuiInputTextDeactivatedState -{ - ImGuiID ID; // widget id owning the text state (which just got deactivated) - ImVector TextA; // text buffer - - ImGuiInputTextDeactivatedState() { memset(this, 0, sizeof(*this)); } - void ClearFreeMemory() { ID = 0; TextA.clear(); } -}; // Internal state of the currently focused/edited text input box // For a given item ID, access with ImGui::GetInputTextState() struct IMGUI_API ImGuiInputTextState { - ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent). ImGuiID ID; // widget id owning the text state int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not. ImVector TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. @@ -1178,14 +1140,13 @@ enum ImGuiNextItemDataFlags_ struct ImGuiNextItemData { ImGuiNextItemDataFlags Flags; - ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemflags_AllowOverlap. float Width; // Set by SetNextItemWidth() ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging) ImGuiCond OpenCond; bool OpenVal; // Set by SetNextItemOpen() ImGuiNextItemData() { memset(this, 0, sizeof(*this)); } - inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()! + inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } // Also cleared manually by ItemAdd()! }; // Status storage for the last submitted item @@ -1214,8 +1175,8 @@ struct IMGUI_API ImGuiStackSizes short SizeOfDisabledStack; ImGuiStackSizes() { memset(this, 0, sizeof(*this)); } - void SetToContextState(ImGuiContext* ctx); - void CompareWithContextState(ImGuiContext* ctx); + void SetToCurrentState(); + void CompareWithCurrentState(); }; // Data saved for each window pushed into the stack @@ -1246,7 +1207,6 @@ struct ImGuiPtrOrIndex // [SECTION] Inputs support //----------------------------------------------------------------------------- -// Bit array for named keys typedef ImBitArray ImBitArrayForNamedKeys; // [Internal] Key ranges @@ -1286,18 +1246,19 @@ enum ImGuiInputEventType enum ImGuiInputSource { ImGuiInputSource_None = 0, - ImGuiInputSource_Mouse, // Note: may be Mouse or TouchScreen or Pen. See io.MouseSource to distinguish them. + ImGuiInputSource_Mouse, ImGuiInputSource_Keyboard, ImGuiInputSource_Gamepad, ImGuiInputSource_Clipboard, // Currently only used by InputText() + ImGuiInputSource_Nav, // Stored in g.ActiveIdSource only ImGuiInputSource_COUNT }; // FIXME: Structures in the union below need to be declared as anonymous unions appears to be an extension? // Using ImVec2() would fail on Clang 'union member 'MousePos' has a non-trivial default constructor' -struct ImGuiInputEventMousePos { float PosX, PosY; ImGuiMouseSource MouseSource; }; -struct ImGuiInputEventMouseWheel { float WheelX, WheelY; ImGuiMouseSource MouseSource; }; -struct ImGuiInputEventMouseButton { int Button; bool Down; ImGuiMouseSource MouseSource; }; +struct ImGuiInputEventMousePos { float PosX, PosY; }; +struct ImGuiInputEventMouseWheel { float WheelX, WheelY; }; +struct ImGuiInputEventMouseButton { int Button; bool Down; }; struct ImGuiInputEventKey { ImGuiKey Key; bool Down; float AnalogValue; }; struct ImGuiInputEventText { unsigned int Char; }; struct ImGuiInputEventAppFocused { bool Focused; }; @@ -1306,7 +1267,6 @@ struct ImGuiInputEvent { ImGuiInputEventType Type; ImGuiInputSource Source; - ImU32 EventId; // Unique, sequential increasing integer to identify an event (if you need to correlate them to other data). union { ImGuiInputEventMousePos MousePos; // if Type == ImGuiInputEventType_MousePos @@ -1331,7 +1291,7 @@ typedef ImS16 ImGuiKeyRoutingIndex; struct ImGuiKeyRoutingData { ImGuiKeyRoutingIndex NextEntryIndex; - ImU16 Mods; // Technically we'd only need 4-bits but for simplify we store ImGuiMod_ values which need 16-bits. ImGuiMod_Shortcut is already translated to Ctrl/Super. + ImU16 Mods; // Technically we'd only need 4 bits but for simplify we store ImGuiMod_ values which need 16 bits. ImU8 RoutingNextScore; // Lower is better (0: perfect score) ImGuiID RoutingCurr; ImGuiID RoutingNext; @@ -1415,7 +1375,6 @@ enum ImGuiInputFlags_ // [SECTION] Clipper support //----------------------------------------------------------------------------- -// Note that Max is exclusive, so perhaps should be using a Begin/End convention. struct ImGuiListClipperRange { int Min; @@ -1448,8 +1407,8 @@ struct ImGuiListClipperData enum ImGuiActivateFlags_ { ImGuiActivateFlags_None = 0, - ImGuiActivateFlags_PreferInput = 1 << 0, // Favor activation that requires keyboard text input (e.g. for Slider/Drag). Default for Enter key. - ImGuiActivateFlags_PreferTweak = 1 << 1, // Favor activation for tweaking with arrows or gamepad (e.g. for Slider/Drag). Default for Space key and if keyboard is not used. + ImGuiActivateFlags_PreferInput = 1 << 0, // Favor activation that requires keyboard text input (e.g. for Slider/Drag). Default if keyboard is available. + ImGuiActivateFlags_PreferTweak = 1 << 1, // Favor activation for tweaking with arrows or gamepad (e.g. for Slider/Drag). Default if keyboard is not available. ImGuiActivateFlags_TryToPreserveState = 1 << 2, // Request widget to preserve state if it can (e.g. InputText will try to preserve cursor/selection) }; @@ -1484,18 +1443,15 @@ enum ImGuiNavMoveFlags_ ImGuiNavMoveFlags_LoopY = 1 << 1, ImGuiNavMoveFlags_WrapX = 1 << 2, // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left) ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful but provided for completeness - ImGuiNavMoveFlags_WrapMask_ = ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_WrapY, ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place) ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, // Store alternate result in NavMoveResultLocalVisible that only comprise elements that are already fully visible (used by PageUp/PageDown) ImGuiNavMoveFlags_ScrollToEdgeY = 1 << 6, // Force scrolling to min/max (used by Home/End) // FIXME-NAV: Aim to remove or reword, probably unnecessary ImGuiNavMoveFlags_Forwarded = 1 << 7, ImGuiNavMoveFlags_DebugNoResult = 1 << 8, // Dummy scoring for debug purpose, don't apply result - ImGuiNavMoveFlags_FocusApi = 1 << 9, // Requests from focus API can land/focus/activate items even if they are marked with _NoTabStop (see NavProcessItemForTabbingRequest() for details) - ImGuiNavMoveFlags_IsTabbing = 1 << 10, // == Focus + Activate if item is Inputable + DontChangeNavHighlight - ImGuiNavMoveFlags_IsPageMove = 1 << 11, // Identify a PageDown/PageUp request. - ImGuiNavMoveFlags_Activate = 1 << 12, // Activate/select target item. - ImGuiNavMoveFlags_NoSelect = 1 << 13, // Don't trigger selection by not setting g.NavJustMovedTo - ImGuiNavMoveFlags_NoSetNavHighlight = 1 << 14, // Do not alter the visible state of keyboard vs mouse nav highlight + ImGuiNavMoveFlags_FocusApi = 1 << 9, + ImGuiNavMoveFlags_Tabbing = 1 << 10, // == Focus + Activate if item is Inputable + DontChangeNavHighlight + ImGuiNavMoveFlags_Activate = 1 << 11, + ImGuiNavMoveFlags_DontSetNavHighlight = 1 << 12, // Do not alter the visible state of keyboard vs mouse nav highlight }; enum ImGuiNavLayer @@ -1603,7 +1559,8 @@ struct ImGuiViewportP : public ImGuiViewport int DrawListsLastFrame[2]; // Last frame number the background (0) and foreground (1) draw lists were used ImDrawList* DrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. ImDrawData DrawDataP; - ImDrawDataBuilder DrawDataBuilder; // Temporary data while building final ImDrawData + ImDrawDataBuilder DrawDataBuilder; + ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!) ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height). ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f. @@ -1637,7 +1594,6 @@ struct ImGuiWindowSettings ImVec2ih Size; bool Collapsed; bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) - bool WantDelete; // Set to invalidate/delete the settings entry ImGuiWindowSettings() { memset(this, 0, sizeof(*this)); } char* GetName() { return (char*)(this + 1); } @@ -1665,7 +1621,6 @@ struct ImGuiSettingsHandler // This is experimental and not officially supported, it'll probably fall short of features, if/when it does we may backtrack. enum ImGuiLocKey : int { - ImGuiLocKey_VersionStr, ImGuiLocKey_TableSizeOne, ImGuiLocKey_TableSizeAllFit, ImGuiLocKey_TableSizeAllDefault, @@ -1696,24 +1651,30 @@ enum ImGuiDebugLogFlags_ ImGuiDebugLogFlags_EventPopup = 1 << 2, ImGuiDebugLogFlags_EventNav = 1 << 3, ImGuiDebugLogFlags_EventClipper = 1 << 4, - ImGuiDebugLogFlags_EventSelection = 1 << 5, - ImGuiDebugLogFlags_EventIO = 1 << 6, - ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO, + ImGuiDebugLogFlags_EventIO = 1 << 5, + ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventIO, ImGuiDebugLogFlags_OutputToTTY = 1 << 10, // Also send output to TTY }; struct ImGuiMetricsConfig { - bool ShowDebugLog = false; - bool ShowStackTool = false; - bool ShowWindowsRects = false; - bool ShowWindowsBeginOrder = false; - bool ShowTablesRects = false; - bool ShowDrawCmdMesh = true; - bool ShowDrawCmdBoundingBoxes = true; - bool ShowAtlasTintedWithTextColor = false; - int ShowWindowsRectsType = -1; - int ShowTablesRectsType = -1; + bool ShowDebugLog; + bool ShowStackTool; + bool ShowWindowsRects; + bool ShowWindowsBeginOrder; + bool ShowTablesRects; + bool ShowDrawCmdMesh; + bool ShowDrawCmdBoundingBoxes; + int ShowWindowsRectsType; + int ShowTablesRectsType; + + ImGuiMetricsConfig() + { + ShowDebugLog = ShowStackTool = ShowWindowsRects = ShowWindowsBeginOrder = ShowTablesRects = false; + ShowDrawCmdMesh = true; + ShowDrawCmdBoundingBoxes = true; + ShowWindowsRectsType = ShowTablesRectsType = -1; + } }; struct ImGuiStackLevelInfo @@ -1767,6 +1728,8 @@ struct ImGuiContext bool Initialized; bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it. ImGuiIO IO; + ImVector InputEventsQueue; // Input events which will be tricked/written into IO structure. + ImVector InputEventsTrail; // Past input events processed in NewFrame(). This is to allow domain-specific application to access e.g mouse/pen trail. ImGuiStyle Style; ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. @@ -1783,12 +1746,6 @@ struct ImGuiContext bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() void* TestEngine; // Test engine user data - // Inputs - ImVector InputEventsQueue; // Input events which will be trickled/written into IO structure. - ImVector InputEventsTrail; // Past input events processed in NewFrame(). This is to allow domain-specific application to access e.g mouse/pen trail. - ImGuiMouseSource InputEventsNextMouseSource; - ImU32 InputEventsNextEventId; - // Windows state ImVector Windows; // Windows, sorted in display order, back to front ImVector WindowsFocusOrder; // Root windows, sorted in focus order, back to front. @@ -1803,10 +1760,7 @@ struct ImGuiContext ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow. ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. ImVec2 WheelingWindowRefMousePos; - int WheelingWindowStartFrame; // This may be set one frame before WheelingWindow is != NULL float WheelingWindowReleaseTimer; - ImVec2 WheelingWindowWheelRemainder; - ImVec2 WheelingAxisAvg; // Item/widgets state and tracking information ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] @@ -1827,7 +1781,7 @@ struct ImGuiContext bool ActiveIdHasBeenEditedThisFrame; ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) ImGuiWindow* ActiveIdWindow; - ImGuiInputSource ActiveIdSource; // Activating source: ImGuiInputSource_Mouse OR ImGuiInputSource_Keyboard OR ImGuiInputSource_Gamepad + ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) int ActiveIdMouseButton; ImGuiID ActiveIdPreviousFrame; bool ActiveIdPreviousFrameIsAlive; @@ -1874,16 +1828,17 @@ struct ImGuiContext ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow' ImGuiID NavId; // Focused item for navigation ImGuiID NavFocusScopeId; // Identify a selection scope (selection code often wants to "clear other items" when landing on an item of the selection set) - ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem() - ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0 - ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat) + ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem() + ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0 + ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat) + ImGuiID NavActivateInputId; // ~~ IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadInput) ? NavId : 0; ImGuiActivateFlags_PreferInput will be set and NavActivateId will be 0. ImGuiActivateFlags NavActivateFlags; ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest). ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest). ImGuiKeyChord NavJustMovedToKeyMods; ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame. ImGuiActivateFlags NavNextActivateFlags; - ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse + ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard. ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) @@ -1894,7 +1849,8 @@ struct ImGuiContext bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd() bool NavInitRequest; // Init request for appearing window to select first item bool NavInitRequestFromMove; - ImGuiNavItemData NavInitResult; // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called) + ImGuiID NavInitResultId; // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called) + ImRect NavInitResultRectRel; // Init request result rectangle (relative to parent window) bool NavMoveSubmitted; // Move request submitted, will process result on next NewFrame() bool NavMoveScoringItems; // Move request submitted, still scoring incoming items bool NavMoveForwardToNextFrame; @@ -1928,6 +1884,7 @@ struct ImGuiContext // Render float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list) + ImGuiMouseCursor MouseCursor; // Drag and Drop bool DragDropActive; @@ -1967,29 +1924,20 @@ struct ImGuiContext ImVector ShrinkWidthBuffer; // Hover Delay system - ImGuiID HoverItemDelayId; - ImGuiID HoverItemDelayIdPreviousFrame; - float HoverItemDelayTimer; // Currently used by IsItemHovered() - float HoverItemDelayClearTimer; // Currently used by IsItemHovered(): grace time before g.TooltipHoverTimer gets cleared. - ImGuiID HoverItemUnlockedStationaryId; // Mouse has once been stationary on this item. Only reset after departing the item. - ImGuiID HoverWindowUnlockedStationaryId; // Mouse has once been stationary on this window. Only reset after departing the window. - - // Mouse state - ImGuiMouseCursor MouseCursor; - float MouseStationaryTimer; // Time the mouse has been stationary (with some loose heuristic) - ImVec2 MouseLastValidPos; + ImGuiID HoverDelayId; + ImGuiID HoverDelayIdPreviousFrame; + float HoverDelayTimer; // Currently used IsItemHovered(), generally inferred from g.HoveredIdTimer but kept uncleared until clear timer elapse. + float HoverDelayClearTimer; // Currently used IsItemHovered(): grace time before g.TooltipHoverTimer gets cleared. // Widget state + ImVec2 MouseLastValidPos; ImGuiInputTextState InputTextState; - ImGuiInputTextDeactivatedState InputTextDeactivatedState; ImFont InputTextPasswordFont; ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets - ImGuiID ColorEditCurrentID; // Set temporarily while inside of the parent-most ColorEdit4/ColorPicker4 (because they call each others). - ImGuiID ColorEditSavedID; // ID we are saving/restoring HS for - float ColorEditSavedHue; // Backup of last Hue associated to LastColor, so we can restore Hue in lossy RGB<>HSV round trips - float ColorEditSavedSat; // Backup of last Saturation associated to LastColor, so we can restore Saturation in lossy RGB<>HSV round trips - ImU32 ColorEditSavedColor; // RGB value with alpha set to 0. + float ColorEditLastHue; // Backup of last Hue associated to LastColor, so we can restore Hue in lossy RGB<>HSV round trips + float ColorEditLastSat; // Backup of last Saturation associated to LastColor, so we can restore Saturation in lossy RGB<>HSV round trips + ImU32 ColorEditLastColor; // RGB value with alpha set to 0. ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker. ImGuiComboPreviewData ComboPreviewData; float SliderGrabClickOffset; @@ -2040,9 +1988,7 @@ struct ImGuiContext ImGuiDebugLogFlags DebugLogFlags; ImGuiTextBuffer DebugLogBuf; ImGuiTextIndex DebugLogIndex; - ImU8 DebugLogClipperAutoDisableFrames; ImU8 DebugLocateFrames; // For DebugLocateItemOnHover(). This is used together with DebugLocateId which is in a hot/cached spot above. - ImS8 DebugBeginReturnValueCullDepth; // Cycle between 0..9 then wrap around. bool DebugItemPickerActive; // Item picker is active (started with DebugStartItemPicker()) ImU8 DebugItemPickerMouseButton; ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this ID @@ -2061,9 +2007,6 @@ struct ImGuiContext ImGuiContext(ImFontAtlas* shared_font_atlas) { - IO.Ctx = this; - InputTextState.Ctx = this; - Initialized = false; FontAtlasOwnedByContext = shared_font_atlas ? false : true; Font = NULL; @@ -2077,16 +2020,12 @@ struct ImGuiContext TestEngineHookItems = false; TestEngine = NULL; - InputEventsNextMouseSource = ImGuiMouseSource_Mouse; - InputEventsNextEventId = 1; - WindowsActiveCount = 0; CurrentWindow = NULL; HoveredWindow = NULL; HoveredWindowUnderMovingWindow = NULL; MovingWindow = NULL; WheelingWindow = NULL; - WheelingWindowStartFrame = -1; WheelingWindowReleaseTimer = 0.0f; DebugHookIdInfo = 0; @@ -2125,11 +2064,11 @@ struct ImGuiContext BeginMenuCount = 0; NavWindow = NULL; - NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0; + NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavActivateInputId = 0; NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0; NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None; NavJustMovedToKeyMods = ImGuiMod_None; - NavInputSource = ImGuiInputSource_Keyboard; + NavInputSource = ImGuiInputSource_None; NavLayer = ImGuiNavLayer_Main; NavIdIsAlive = false; NavMousePosDirty = false; @@ -2138,6 +2077,7 @@ struct ImGuiContext NavAnyRequest = false; NavInitRequest = false; NavInitRequestFromMove = false; + NavInitResultId = 0; NavMoveSubmitted = false; NavMoveScoringItems = false; NavMoveForwardToNextFrame = false; @@ -2156,6 +2096,7 @@ struct ImGuiContext NavWindowingToggleLayer = false; DimBgRatio = 0.0f; + MouseCursor = ImGuiMouseCursor_Arrow; DragDropActive = DragDropWithinSource = DragDropWithinTarget = false; DragDropSourceFlags = ImGuiDragDropFlags_None; @@ -2175,17 +2116,13 @@ struct ImGuiContext TablesTempDataStacked = 0; CurrentTabBar = NULL; - HoverItemDelayId = HoverItemDelayIdPreviousFrame = HoverItemUnlockedStationaryId = HoverWindowUnlockedStationaryId = 0; - HoverItemDelayTimer = HoverItemDelayClearTimer = 0.0f; - - MouseCursor = ImGuiMouseCursor_Arrow; - MouseStationaryTimer = 0.0f; + HoverDelayId = HoverDelayIdPreviousFrame = 0; + HoverDelayTimer = HoverDelayClearTimer = 0.0f; TempInputId = 0; ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_; - ColorEditCurrentID = ColorEditSavedID = 0; - ColorEditSavedHue = ColorEditSavedSat = 0.0f; - ColorEditSavedColor = 0; + ColorEditLastHue = ColorEditLastSat = 0.0f; + ColorEditLastColor = 0; SliderGrabClickOffset = 0.0f; SliderCurrentAccum = 0.0f; SliderCurrentAccumDirty = false; @@ -2218,9 +2155,7 @@ struct ImGuiContext DebugLogFlags = ImGuiDebugLogFlags_OutputToTTY; DebugLocateId = 0; - DebugLogClipperAutoDisableFrames = 0; DebugLocateFrames = 0; - DebugBeginReturnValueCullDepth = -1; DebugItemPickerActive = false; DebugItemPickerMouseButton = ImGuiMouseButton_Left; DebugItemPickerBreakId = 0; @@ -2256,15 +2191,14 @@ struct IMGUI_API ImGuiWindowTempData ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. ImVec1 GroupOffset; - ImVec2 CursorStartPosLossyness;// Record the loss of precision of CursorStartPos due to really large scrolling amount. This is used by clipper to compensate and fix the most common use case of large scroll area. + ImVec2 CursorStartPosLossyness;// Record the loss of precision of CursorStartPos due to really large scrolling amount. This is used by clipper to compensentate and fix the most common use case of large scroll area. // Keyboard/Gamepad navigation ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) short NavLayersActiveMask; // Which layers have been written to (result from previous frame) short NavLayersActiveMaskNext;// Which layers have been written to (accumulator for current frame) - bool NavIsScrollPushableX; // Set when current work location may be scrolled horizontally when moving left / right. This is generally always true UNLESS within a column. bool NavHideHighlightOneFrame; - bool NavWindowHasScrollY; // Set per window when scrolling can be used (== ScrollMax.y > 0.0f) + bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) // Miscellaneous bool MenuBarAppending; // FIXME: Remove this @@ -2290,7 +2224,6 @@ struct IMGUI_API ImGuiWindowTempData // Storage for one window struct IMGUI_API ImGuiWindow { - ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent). char* Name; // Window name, owned by the window. ImGuiID ID; // == ImHashStr(Name) ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_ @@ -2304,9 +2237,6 @@ struct IMGUI_API ImGuiWindow ImVec2 WindowPadding; // Window padding at the time of Begin(). float WindowRounding; // Window rounding at the time of Begin(). May be clamped lower to avoid rendering artifacts with title bar, menu bar etc. float WindowBorderSize; // Window border size at the time of Begin(). - float DecoOuterSizeX1, DecoOuterSizeY1; // Left/Up offsets. Sum of non-scrolling outer decorations (X1 generally == 0.0f. Y1 generally = TitleBarHeight + MenuBarHeight). Locked during Begin(). - float DecoOuterSizeX2, DecoOuterSizeY2; // Right/Down offsets (X2 generally == ScrollbarSize.x, Y2 == ScrollbarSizes.y). - float DecoInnerSizeX1, DecoInnerSizeY1; // Applied AFTER/OVER InnerRect. Specialized for Tables as they use specialized form of clipping and frozen rows/columns are inside InnerRect (and not part of regular decoration sizes). int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! ImGuiID MoveId; // == window->GetID("#MOVE") ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) @@ -2384,7 +2314,6 @@ struct IMGUI_API ImGuiWindow ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1) ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space - ImVec2 NavPreferredScoringPosRel[ImGuiNavLayer_COUNT]; // Preferred X/Y position updated when moving on a given axis, reset to FLT_MAX. ImGuiID NavRootFocusScopeId; // Focus Scope ID at the time of Begin() int MemoryDrawListIdxCapacity; // Backup of last idx/vtx count, so when waking up the window we can preallocate and avoid iterative alloc/copy @@ -2402,10 +2331,10 @@ public: // We don't use g.FontSize because the window may be != g.CurrentWindow. ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } - float CalcFontSize() const { ImGuiContext& g = *Ctx; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } - float TitleBarHeight() const { ImGuiContext& g = *Ctx; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; } + float CalcFontSize() const { ImGuiContext& g = *GImGui; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } + float TitleBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; } ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } - float MenuBarHeight() const { ImGuiContext& g = *Ctx; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; } + float MenuBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; } ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } }; @@ -2442,7 +2371,7 @@ struct ImGuiTabItem float RequestedWidth; // Width optionally requested by caller, -1.0f is unused ImS32 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames ImS16 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable - ImS16 IndexDuringLayout; // Index only used during TabBarLayout(). Tabs gets reordered so 'Tabs[n].IndexDuringLayout == n' but may mismatch during additions. + ImS16 IndexDuringLayout; // Index only used during TabBarLayout() bool WantClose; // Marked as closed by SetTabItemClosed() ImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; RequestedWidth = -1.0f; NameOffset = -1; BeginOrder = IndexDuringLayout = -1; } @@ -2484,6 +2413,12 @@ struct IMGUI_API ImGuiTabBar ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer. ImGuiTabBar(); + int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } + const char* GetTabName(const ImGuiTabItem* tab) const + { + IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size); + return TabsNames.Buf.Data + tab->NameOffset; + } }; //----------------------------------------------------------------------------- @@ -2491,13 +2426,14 @@ struct IMGUI_API ImGuiTabBar //----------------------------------------------------------------------------- #define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color. -#define IMGUI_TABLE_MAX_COLUMNS 512 // May be further lifted +#define IMGUI_TABLE_MAX_COLUMNS 64 // sizeof(ImU64) * 8. This is solely because we frequently encode columns set in a ImU64. +#define IMGUI_TABLE_MAX_DRAW_CHANNELS (4 + 64 * 2) // See TableSetupDrawChannels() // Our current column maximum is 64 but we may raise that in the future. -typedef ImS16 ImGuiTableColumnIdx; -typedef ImU16 ImGuiTableDrawChannelIdx; +typedef ImS8 ImGuiTableColumnIdx; +typedef ImU8 ImGuiTableDrawChannelIdx; -// [Internal] sizeof() ~ 112 +// [Internal] sizeof() ~ 104 // We use the terminology "Enabled" to refer to a column that is not Hidden by user/api. // We use the terminology "Clipped" to refer to a column that is out of sight because of scrolling/clipping. // This is in contrast with some user-facing api such as IsItemVisible() / IsRectVisible() which use "Visible" to mean "not clipped". @@ -2543,7 +2479,7 @@ struct ImGuiTableColumn ImU8 SortDirection : 2; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending ImU8 SortDirectionsAvailCount : 2; // Number of available sort directions (0 to 3) ImU8 SortDirectionsAvailMask : 4; // Mask of available sort directions (1-bit each) - ImU8 SortDirectionsAvailList; // Ordered list of available sort directions (2-bits each, total 8-bits) + ImU8 SortDirectionsAvailList; // Ordered of available sort directions (2-bits each) ImGuiTableColumn() { @@ -2566,21 +2502,16 @@ struct ImGuiTableCellData ImGuiTableColumnIdx Column; // Column number }; -// Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs. Does that means they could be moved to ImGuiTableTempData?) +// Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs, does that needs they could be moved to ImGuiTableTempData ?) struct ImGuiTableInstanceData { - ImGuiID TableInstanceID; - float LastOuterHeight; // Outer height from last frame - float LastFirstRowHeight; // Height of first row from last frame (FIXME: this is used as "header height" and may be reworked) - float LastFrozenHeight; // Height of frozen section from last frame - int HoveredRowLast; // Index of row which was hovered last frame. - int HoveredRowNext; // Index of row hovered this frame, set after encountering it. + float LastOuterHeight; // Outer height from last frame // FIXME: multi-instance issue (#3955) + float LastFirstRowHeight; // Height of first row from last frame // FIXME: possible multi-instance issue? - ImGuiTableInstanceData() { TableInstanceID = 0; LastOuterHeight = LastFirstRowHeight = LastFrozenHeight = 0.0f; HoveredRowLast = HoveredRowNext = -1; } + ImGuiTableInstanceData() { LastOuterHeight = LastFirstRowHeight = 0.0f; } }; -// FIXME-TABLE: more transient data could be stored in a stacked ImGuiTableTempData: e.g. SortSpecs, incoming RowData -// sizeof() ~ 580 bytes + heap allocs described in TableBeginInitMemory() +// FIXME-TABLE: more transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData struct IMGUI_API ImGuiTable { ImGuiID ID; @@ -2590,9 +2521,10 @@ struct IMGUI_API ImGuiTable ImSpan Columns; // Point within RawData[] ImSpan DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1) ImSpan RowCellData; // Point within RawData[]. Store cells background requests for current row. - ImBitArrayPtr EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map - ImBitArrayPtr EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data - ImBitArrayPtr VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect) + ImU64 EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map + ImU64 EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data + ImU64 VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect) + ImU64 RequestOutputMaskByIndex; // Column Index -> IsVisible || AutoFit (== expect user to submit items) ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order) int SettingsOffset; // Offset in g.SettingsTables int LastFrameActive; @@ -2684,8 +2616,6 @@ struct IMGUI_API ImGuiTable bool IsResetDisplayOrderRequest; bool IsUnfrozenRows; // Set when we got past the frozen row. bool IsDefaultSizingPolicy; // Set if user didn't explicitly set a sizing policy in BeginTable() - bool HasScrollbarYCurr; // Whether ANY instance of this table had a vertical scrollbar during the current frame. - bool HasScrollbarYPrev; // Whether ANY instance of this table had a vertical scrollbar during the previous. bool MemoryCompacted; bool HostSkipItems; // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis @@ -2696,7 +2626,6 @@ struct IMGUI_API ImGuiTable // Transient data that are only needed between BeginTable() and EndTable(), those buffers are shared (1 per level of stacked table). // - Accessing those requires chasing an extra pointer so for very frequently used data we leave them in the main table structure. // - We also leave out of this structure data that tend to be particularly useful for debugging/metrics. -// sizeof() ~ 112 bytes. struct IMGUI_API ImGuiTableTempData { int TableIndex; // Index in g.Tables.Buf[] pool @@ -2781,14 +2710,12 @@ namespace ImGui IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0); IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0); IMGUI_API void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size); - IMGUI_API void SetWindowHiddendAndSkipItemsForCurrentFrame(ImGuiWindow* window); inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); } inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); } - inline ImVec2 WindowPosRelToAbs(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x + off.x, p.y + off.y); } // Windows: Display Order and Focus Order - IMGUI_API void FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags = 0); - IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags); + IMGUI_API void FocusWindow(ImGuiWindow* window); + IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window); IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window); IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window); IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window); @@ -2802,7 +2729,6 @@ namespace ImGui inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. - IMGUI_API void AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector* out_list, ImDrawList* draw_list); // Init IMGUI_API void Initialize(); @@ -2827,16 +2753,13 @@ namespace ImGui IMGUI_API void MarkIniSettingsDirty(); IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); IMGUI_API void ClearIniSettings(); + IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); + IMGUI_API ImGuiWindowSettings* FindOrCreateWindowSettings(const char* name); IMGUI_API void AddSettingsHandler(const ImGuiSettingsHandler* handler); IMGUI_API void RemoveSettingsHandler(const char* type_name); IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); - // Settings - Windows - IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); - IMGUI_API ImGuiWindowSettings* FindWindowSettingsByID(ImGuiID id); - IMGUI_API ImGuiWindowSettings* FindWindowSettingsByWindow(ImGuiWindow* window); - IMGUI_API void ClearWindowSettings(const char* name); - // Localization IMGUI_API void LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count); inline const char* LocalizeGetMsg(ImGuiLocKey key) { ImGuiContext& g = *GImGui; const char* msg = g.LocalizationTable[key]; return msg ? msg : "*Missing Text*"; } @@ -2856,6 +2779,7 @@ namespace ImGui //#endif // Basic Accessors + inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.LastItemData.ID; } // Get ID of last item (~~ often same ImGui::GetID(label) beforehand) inline ImGuiItemStatusFlags GetItemStatusFlags(){ ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; } inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.InFlags; } inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } @@ -2869,14 +2793,12 @@ namespace ImGui IMGUI_API void MarkItemEdited(ImGuiID id); // Mark data associated to given item as "edited", used by IsItemDeactivatedAfterEdit() function. IMGUI_API void PushOverrideID(ImGuiID id); // Push given value as-is at the top of the ID stack (whereas PushID combines old and new hashes) IMGUI_API ImGuiID GetIDWithSeed(const char* str_id_begin, const char* str_id_end, ImGuiID seed); - IMGUI_API ImGuiID GetIDWithSeed(int n, ImGuiID seed); // Basic Helpers for widget code IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); inline void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f) { ItemSize(bb.GetSize(), text_baseline_y); } // FIXME: This is a misleading API since we expect CursorPos to be bb.Min. IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemFlags extra_flags = 0); - IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags); - IMGUI_API bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags = 0); + IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id); IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); @@ -2889,7 +2811,6 @@ namespace ImGui // Parameter stacks (shared) IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); IMGUI_API void PopItemFlag(); - IMGUI_API const ImGuiDataVarInfo* GetStyleVarInfo(ImGuiStyleVar idx); // Logging/Capture IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. @@ -2905,11 +2826,10 @@ namespace ImGui IMGUI_API void ClosePopupsExceptModals(); IMGUI_API bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags); IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); - IMGUI_API bool BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags); + IMGUI_API void BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags); IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow* window); IMGUI_API ImGuiWindow* GetTopMostPopupModal(); IMGUI_API ImGuiWindow* GetTopMostAndVisiblePopupModal(); - IMGUI_API ImGuiWindow* FindBlockingModal(ImGuiWindow* window); IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy); @@ -2933,44 +2853,33 @@ namespace ImGui IMGUI_API void NavMoveRequestCancel(); IMGUI_API void NavMoveRequestApplyResult(); IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); - IMGUI_API void NavClearPreferredPosForAxis(ImGuiAxis axis); - IMGUI_API void NavUpdateCurrentWindowIsScrollPushableX(); + IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. IMGUI_API void SetNavWindow(ImGuiWindow* window); IMGUI_API void SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel); - // Focus/Activation - // This should be part of a larger set of API: FocusItem(offset = -1), FocusItemByID(id), ActivateItem(offset = -1), ActivateItemByID(id) etc. which are - // much harder to design and implement than expected. I have a couple of private branches on this matter but it's not simple. For now implementing the easy ones. - IMGUI_API void FocusItem(); // Focus last item (no selection/activation). - IMGUI_API void ActivateItemByID(ImGuiID id); // Activate an item by ID (button, checkbox, tree node etc.). Activation is queued and processed on the next frame when the item is encountered again. - // Inputs // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. inline bool IsNamedKey(ImGuiKey key) { return key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END; } - inline bool IsNamedKeyOrModKey(ImGuiKey key) { return (key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super || key == ImGuiMod_Shortcut; } + inline bool IsNamedKeyOrModKey(ImGuiKey key) { return (key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super; } inline bool IsLegacyKey(ImGuiKey key) { return key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_LegacyNativeKey_END; } inline bool IsKeyboardKey(ImGuiKey key) { return key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END; } inline bool IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_END; } inline bool IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; } inline bool IsAliasKey(ImGuiKey key) { return key >= ImGuiKey_Aliases_BEGIN && key < ImGuiKey_Aliases_END; } - inline ImGuiKeyChord ConvertShortcutMod(ImGuiKeyChord key_chord) { ImGuiContext& g = *GImGui; IM_ASSERT_PARANOID(key_chord & ImGuiMod_Shortcut); return (key_chord & ~ImGuiMod_Shortcut) | (g.IO.ConfigMacOSXBehaviors ? ImGuiMod_Super : ImGuiMod_Ctrl); } - inline ImGuiKey ConvertSingleModFlagToKey(ImGuiContext* ctx, ImGuiKey key) + inline ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key) { - ImGuiContext& g = *ctx; if (key == ImGuiMod_Ctrl) return ImGuiKey_ReservedForModCtrl; if (key == ImGuiMod_Shift) return ImGuiKey_ReservedForModShift; if (key == ImGuiMod_Alt) return ImGuiKey_ReservedForModAlt; if (key == ImGuiMod_Super) return ImGuiKey_ReservedForModSuper; - if (key == ImGuiMod_Shortcut) return (g.IO.ConfigMacOSXBehaviors ? ImGuiKey_ReservedForModSuper : ImGuiKey_ReservedForModCtrl); return key; } - IMGUI_API ImGuiKeyData* GetKeyData(ImGuiContext* ctx, ImGuiKey key); - inline ImGuiKeyData* GetKeyData(ImGuiKey key) { ImGuiContext& g = *GImGui; return GetKeyData(&g, key); } + IMGUI_API ImGuiKeyData* GetKeyData(ImGuiKey key); IMGUI_API void GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size); inline ImGuiKey MouseButtonToKey(ImGuiMouseButton button) { IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT); return (ImGuiKey)(ImGuiKey_MouseLeft + button); } IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f); - IMGUI_API ImVec2 GetKeyMagnitude2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down); + IMGUI_API ImVec2 GetKeyVector2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down); IMGUI_API float GetNavTweakPressedAmount(ImGuiAxis axis); IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate); IMGUI_API void GetTypematicRepeatRate(ImGuiInputFlags flags, float* repeat_delay, float* repeat_rate); @@ -2990,10 +2899,9 @@ namespace ImGui // Please open a GitHub Issue to submit your usage scenario or if there's a use case you need solved. IMGUI_API ImGuiID GetKeyOwner(ImGuiKey key); IMGUI_API void SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0); - IMGUI_API void SetKeyOwnersForKeyChord(ImGuiKeyChord key, ImGuiID owner_id, ImGuiInputFlags flags = 0); IMGUI_API void SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags = 0); // Set key owner to last item if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'. IMGUI_API bool TestKeyOwner(ImGuiKey key, ImGuiID owner_id); // Test that key is either not owned, either owned by 'owner_id' - inline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiContext* ctx, ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(ctx, key); IM_ASSERT(IsNamedKey(key)); return &ctx->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; } + inline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(key); IM_ASSERT(IsNamedKey(key)); return &GImGui->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; } // [EXPERIMENTAL] High-Level: Input Access functions w/ support for Key/Input Ownership // - Important: legacy IsKeyPressed(ImGuiKey, bool repeat=true) _DEFAULTS_ to repeat, new IsKeyPressed() requires _EXPLICIT_ ImGuiInputFlags_Repeat flag. @@ -3058,8 +2966,7 @@ namespace ImGui IMGUI_API void TableOpenContextMenu(int column_n = -1); IMGUI_API void TableSetColumnWidth(int column_n, float width); IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); - IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. - IMGUI_API int TableGetHoveredRow(); // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet. + IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. IMGUI_API float TableGetHeaderRowHeight(); IMGUI_API void TablePushBackgroundChannel(); IMGUI_API void TablePopBackgroundChannel(); @@ -3078,8 +2985,7 @@ namespace ImGui IMGUI_API void TableDrawContextMenu(ImGuiTable* table); IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table); IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); - inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; } - inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; } + inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; } IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column); @@ -3091,7 +2997,7 @@ namespace ImGui IMGUI_API void TableEndCell(ImGuiTable* table); IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n); IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n); - IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0); + IMGUI_API ImGuiID TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no = 0); IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); @@ -3110,22 +3016,15 @@ namespace ImGui IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id); // Tab Bars - inline ImGuiTabBar* GetCurrentTabBar() { ImGuiContext& g = *GImGui; return g.CurrentTabBar; } IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); - IMGUI_API ImGuiTabItem* TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order); - IMGUI_API ImGuiTabItem* TabBarGetCurrentTab(ImGuiTabBar* tab_bar); - inline int TabBarGetTabOrder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { return tab_bar->Tabs.index_from_ptr(tab); } - IMGUI_API const char* TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); - IMGUI_API void TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); - IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset); - IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImVec2 mouse_pos); + IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset); + IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, ImVec2 mouse_pos); IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar); - IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window); + IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags); IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker); - IMGUI_API ImVec2 TabItemCalcSize(ImGuiWindow* window); IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); IMGUI_API void TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped); @@ -3155,28 +3054,25 @@ namespace ImGui // Widgets IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); - IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); - IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0); - IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags, float thickness = 1.0f); - IMGUI_API void SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_width); - IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value); - IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value); - - // Widgets: Window Decorations IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos); IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); + IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); IMGUI_API void Scrollbar(ImGuiAxis axis); IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags flags); + IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col); IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis); IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners IMGUI_API ImGuiID GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir); + IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); + IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value); + IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value); // Widgets low-level behaviors IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags); IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); - IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f, ImU32 bg_col = 0); + IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f); IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); IMGUI_API void TreePushOverrideID(ImGuiID id); IMGUI_API void TreeNodeSetOpen(ImGuiID id, bool open); @@ -3202,7 +3098,6 @@ namespace ImGui // InputText IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); - IMGUI_API void InputTextDeactivateHook(ImGuiID id); IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags); IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL); inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); } @@ -3214,7 +3109,7 @@ namespace ImGui IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags); // Plot - IMGUI_API int PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg); + IMGUI_API int PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size); // Shade functions (write over already created vertices) IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); @@ -3241,7 +3136,7 @@ namespace ImGui IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end); IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns); - IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label); + IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label); IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); IMGUI_API void DebugNodeFont(ImFont* font); IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph); @@ -3255,7 +3150,6 @@ namespace ImGui IMGUI_API void DebugNodeWindowsList(ImVector* windows, const char* label); IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack); IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport); - IMGUI_API void DebugRenderKeyboardPreview(ImDrawList* draw_list); IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb); // Obsolete functions @@ -3266,7 +3160,7 @@ namespace ImGui // Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets that used FocusableItemRegister(): // (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool tab_focused = FocusableItemRegister(...)' // (Old) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool tab_focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0' - // (New) IMGUI_VERSION_NUM >= 18413: using 'ItemAdd(..., ImGuiItemFlags_Inputable)' and 'bool tab_focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_FocusedTabbing) != 0 || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))' (WIP) + // (New) IMGUI_VERSION_NUM >= 18413: using 'ItemAdd(..., ImGuiItemFlags_Inputable)' and 'bool tab_focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_FocusedTabbing) != 0 || g.NavActivateInputId == id' (WIP) // Widget code are simplified as there's no need to call FocusableItemUnregister() while managing the transition from regular widget to TempInputText() inline bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id) { IM_ASSERT(0); IM_UNUSED(window); IM_UNUSED(id); return false; } // -> pass ImGuiItemAddFlags_Inputable flag to ItemAdd() inline void FocusableItemUnregister(ImGuiWindow* window) { IM_ASSERT(0); IM_UNUSED(window); } // -> unnecessary: TempInputText() uses ImGuiInputTextFlags_MergedItem @@ -3306,15 +3200,14 @@ IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table //----------------------------------------------------------------------------- #ifdef IMGUI_ENABLE_TEST_ENGINE -extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, ImGuiID id, const ImRect& bb, const ImGuiLastItemData* item_data); // item_data may be NULL +extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...); extern const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext* ctx, ImGuiID id); -// In IMGUI_VERSION_NUM >= 18934: changed IMGUI_TEST_ENGINE_ITEM_ADD(bb,id) to IMGUI_TEST_ENGINE_ITEM_ADD(id,bb,item_data); -#define IMGUI_TEST_ENGINE_ITEM_ADD(_ID,_BB,_ITEM_DATA) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _ID, _BB, _ITEM_DATA) // Register item bounding box -#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) -#define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log +#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) // Register item bounding box +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) +#define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log #else #define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) ((void)0) #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)g) diff --git a/3rdparty/bgfx/3rdparty/dear-imgui/imgui_tables.cpp b/3rdparty/bgfx/3rdparty/dear-imgui/imgui_tables.cpp index 33c9d05d9de..66a46573b95 100644 --- a/3rdparty/bgfx/3rdparty/dear-imgui/imgui_tables.cpp +++ b/3rdparty/bgfx/3rdparty/dear-imgui/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.8 WIP +// dear imgui, v1.89.1 WIP // (tables and columns code) /* @@ -80,20 +80,20 @@ Index of this file: // - outer_size.x <= 0.0f -> Right-align from window/work-rect right-most edge. With -FLT_MIN or 0.0f will align exactly on right-most edge. // - outer_size.x > 0.0f -> Set Fixed width. // Y with ScrollX/ScrollY disabled: we output table directly in current window -// - outer_size.y < 0.0f -> Bottom-align (but will auto extend, unless _NoHostExtendY is set). Not meaningful if parent window can vertically scroll. +// - outer_size.y < 0.0f -> Bottom-align (but will auto extend, unless _NoHostExtendY is set). Not meaningful is parent window can vertically scroll. // - outer_size.y = 0.0f -> No minimum height (but will auto extend, unless _NoHostExtendY is set) // - outer_size.y > 0.0f -> Set Minimum height (but will auto extend, unless _NoHostExtenY is set) // Y with ScrollX/ScrollY enabled: using a child window for scrolling -// - outer_size.y < 0.0f -> Bottom-align. Not meaningful if parent window can vertically scroll. +// - outer_size.y < 0.0f -> Bottom-align. Not meaningful is parent window can vertically scroll. // - outer_size.y = 0.0f -> Bottom-align, consistent with BeginChild(). Not recommended unless table is last item in parent window. // - outer_size.y > 0.0f -> Set Exact height. Recommended when using Scrolling on any axis. //----------------------------------------------------------------------------- // Outer size is also affected by the NoHostExtendX/NoHostExtendY flags. -// Important to note how the two flags have slightly different behaviors! +// Important to that note how the two flags have slightly different behaviors! // - ImGuiTableFlags_NoHostExtendX -> Make outer width auto-fit to columns (overriding outer_size.x value). Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. // - ImGuiTableFlags_NoHostExtendY -> Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY is disabled. Data below the limit will be clipped and not visible. // In theory ImGuiTableFlags_NoHostExtendY could be the default and any non-scrolling tables with outer_size.y != 0.0f would use exact height. -// This would be consistent but perhaps less useful and more confusing (as vertically clipped items are not useful and not easily noticeable). +// This would be consistent but perhaps less useful and more confusing (as vertically clipped items are not easily noticeable) //----------------------------------------------------------------------------- // About 'inner_width': // With ScrollX disabled: @@ -112,16 +112,15 @@ Index of this file: //----------------------------------------------------------------------------- // COLUMNS SIZING POLICIES -// (Reference: ImGuiTableFlags_SizingXXX flags and ImGuiTableColumnFlags_WidthXXX flags) //----------------------------------------------------------------------------- // About overriding column sizing policy and width/weight with TableSetupColumn(): -// We use a default parameter of -1 for 'init_width'/'init_weight'. +// We use a default parameter of 'init_width_or_weight == -1'. // - with ImGuiTableColumnFlags_WidthFixed, init_width <= 0 (default) --> width is automatic // - with ImGuiTableColumnFlags_WidthFixed, init_width > 0 (explicit) --> width is custom // - with ImGuiTableColumnFlags_WidthStretch, init_weight <= 0 (default) --> weight is 1.0f // - with ImGuiTableColumnFlags_WidthStretch, init_weight > 0 (explicit) --> weight is custom // Widths are specified _without_ CellPadding. If you specify a width of 100.0f, the column will be cover (100.0f + Padding * 2.0f) -// and you can fit a 100.0f wide item in it without clipping and with padding honored. +// and you can fit a 100.0f wide item in it without clipping and with full padding. //----------------------------------------------------------------------------- // About default sizing policy (if you don't specify a ImGuiTableColumnFlags_WidthXXXX flag) // - with Table policy ImGuiTableFlags_SizingFixedFit --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is equal to contents width @@ -135,10 +134,10 @@ Index of this file: // - using mixed policies with ScrollX does not make much sense, as using Stretch columns with ScrollX does not make much sense in the first place! // that is, unless 'inner_width' is passed to BeginTable() to explicitly provide a total width to layout columns in. // - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the width of the maximum contents. -// - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weights/widths. +// - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weight/widths. //----------------------------------------------------------------------------- // About using column width: -// If a column is manually resizable or has a width specified with TableSetupColumn(): +// If a column is manual resizable or has a width specified with TableSetupColumn(): // - you may use GetContentRegionAvail().x to query the width available in a given column. // - right-side alignment features such as SetNextItemWidth(-x) or PushItemWidth(-x) will rely on this width. // If the column is not resizable and has no width specified with TableSetupColumn(): @@ -152,7 +151,7 @@ Index of this file: // TABLES CLIPPING/CULLING //----------------------------------------------------------------------------- // About clipping/culling of Rows in Tables: -// - For large numbers of rows, it is recommended you use ImGuiListClipper to submit only visible rows. +// - For large numbers of rows, it is recommended you use ImGuiListClipper to only submit visible rows. // ImGuiListClipper is reliant on the fact that rows are of equal height. // See 'Demo->Tables->Vertical Scrolling' or 'Demo->Tables->Advanced' for a demo of using the clipper. // - Note that auto-resizing columns don't play well with using the clipper. @@ -169,7 +168,7 @@ Index of this file: // - Case C: column is hidden explicitly by the user (e.g. via the context menu, or _DefaultHide column flag, etc.). // // [A] [B] [C] -// TableNextColumn(): true false false -> [userland] when TableNextColumn() / TableSetColumnIndex() returns false, user can skip submitting items but only if the column doesn't contribute to row height. +// TableNextColumn(): true false false -> [userland] when TableNextColumn() / TableSetColumnIndex() return false, user can skip submitting items but only if the column doesn't contribute to row height. // SkipItems: false false true -> [internal] when SkipItems is true, most widgets will early out if submitted, resulting is no layout output. // ClipRect: normal zero-width zero-width -> [internal] when ClipRect is zero, ItemAdd() will return false and most widgets will early out mid-way. // ImDrawList output: normal dummy dummy -> [internal] when using the dummy channel, ImDrawList submissions (if any) will be wasted (because cliprect is zero-width anyway). @@ -189,16 +188,20 @@ Index of this file: #define _CRT_SECURE_NO_WARNINGS #endif +#include "imgui.h" +#ifndef IMGUI_DISABLE + #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif - -#include "imgui.h" -#ifndef IMGUI_DISABLE #include "imgui_internal.h" // System includes +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else #include // intptr_t +#endif // Visual Studio warnings #ifdef _MSC_VER @@ -312,11 +315,11 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG return false; // Sanity checks - IM_ASSERT(columns_count > 0 && columns_count < IMGUI_TABLE_MAX_COLUMNS); + IM_ASSERT(columns_count > 0 && columns_count <= IMGUI_TABLE_MAX_COLUMNS && "Only 1..64 columns allowed!"); if (flags & ImGuiTableFlags_ScrollX) IM_ASSERT(inner_width >= 0.0f); - // If an outer size is specified ahead we will be able to early out when not visible. Exact clipping criteria may evolve. + // If an outer size is specified ahead we will be able to early out when not visible. Exact clipping rules may evolve. const bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0; const ImVec2 avail_size = GetContentRegionAvail(); ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f); @@ -329,7 +332,11 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG // Acquire storage for the table ImGuiTable* table = g.Tables.GetOrAddByKey(id); + const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1; + const ImGuiID instance_id = id + instance_no; const ImGuiTableFlags table_last_flags = table->Flags; + if (instance_no > 0) + IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID"); // Acquire temporary buffers const int table_idx = g.Tables.GetIndex(table); @@ -345,32 +352,17 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG flags = TableFixFlags(flags, outer_window); // Initialize - const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1; table->ID = id; table->Flags = flags; + table->InstanceCurrent = (ImS16)instance_no; table->LastFrameActive = g.FrameCount; table->OuterWindow = table->InnerWindow = outer_window; table->ColumnsCount = columns_count; table->IsLayoutLocked = false; table->InnerWidth = inner_width; temp_data->UserOuterSize = outer_size; - - // Instance data (for instance 0, TableID == TableInstanceID) - ImGuiID instance_id; - table->InstanceCurrent = (ImS16)instance_no; - if (instance_no > 0) - { - IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID"); - if (table->InstanceDataExtra.Size < instance_no) - table->InstanceDataExtra.push_back(ImGuiTableInstanceData()); - instance_id = GetIDWithSeed(instance_no, GetIDWithSeed("##Instances", NULL, id)); // Push "##Instances" followed by (int)instance_no in ID stack. - } - else - { - instance_id = id; - } - ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); - table_instance->TableInstanceID = instance_id; + if (instance_no > 0 && table->InstanceDataExtra.Size < instance_no) + table->InstanceDataExtra.push_back(ImGuiTableInstanceData()); // When not using a child window, WorkRect.Max will grow as we append contents. if (use_child_window) @@ -403,14 +395,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->OuterRect = table->InnerWindow->Rect(); table->InnerRect = table->InnerWindow->InnerRect; IM_ASSERT(table->InnerWindow->WindowPadding.x == 0.0f && table->InnerWindow->WindowPadding.y == 0.0f && table->InnerWindow->WindowBorderSize == 0.0f); - - // When using multiple instances, ensure they have the same amount of horizontal decorations (aka vertical scrollbar) so stretched columns can be aligned) - if (instance_no == 0) - { - table->HasScrollbarYPrev = table->HasScrollbarYCurr; - table->HasScrollbarYCurr = false; - } - table->HasScrollbarYCurr |= table->InnerWindow->ScrollbarY; } else { @@ -420,9 +404,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG } // Push a standardized ID for both child-using and not-child-using tables - PushOverrideID(id); - if (instance_no > 0) - PushOverrideID(instance_id); // FIXME: Somehow this is not resolved by stack-tool, even tho GetIDWithSeed() submitted the symbol. + PushOverrideID(instance_id); // Backup a copy of host window members we will modify ImGuiWindow* inner_window = table->InnerWindow; @@ -474,13 +456,12 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->IsUnfrozenRows = true; table->DeclColumnsCount = 0; - // Using opaque colors facilitate overlapping lines of the grid, otherwise we'd need to improve TableDrawBorders() + // Using opaque colors facilitate overlapping elements of the grid table->BorderColorStrong = GetColorU32(ImGuiCol_TableBorderStrong); table->BorderColorLight = GetColorU32(ImGuiCol_TableBorderLight); // Make table current g.CurrentTable = table; - outer_window->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX(); outer_window->DC.CurrentTableIdx = table_idx; if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly. inner_window->DC.CurrentTableIdx = table_idx; @@ -488,7 +469,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG if ((table_last_flags & ImGuiTableFlags_Reorderable) && (flags & ImGuiTableFlags_Reorderable) == 0) table->IsResetDisplayOrderRequest = true; - // Mark as used to avoid GC + // Mark as used if (table_idx >= g.TablesLastTimeActive.Size) g.TablesLastTimeActive.resize(table_idx + 1, -1.0f); g.TablesLastTimeActive[table_idx] = (float)g.Time; @@ -581,40 +562,34 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG } // For reference, the average total _allocation count_ for a table is: -// + 0 (for ImGuiTable instance, we are pooling allocations in g.Tables[]) +// + 0 (for ImGuiTable instance, we are pooling allocations in g.Tables) // + 1 (for table->RawData allocated below) // + 1 (for table->ColumnsNames, if names are used) -// Shared allocations for the maximum number of simultaneously nested tables (generally a very small number) +// Shared allocations per number of nested tables // + 1 (for table->Splitter._Channels) // + 2 * active_channels_count (for ImDrawCmd and ImDrawIdx buffers inside channels) -// Where active_channels_count is variable but often == columns_count or == columns_count + 1, see TableSetupDrawChannels() for details. +// Where active_channels_count is variable but often == columns_count or columns_count + 1, see TableSetupDrawChannels() for details. // Unused channels don't perform their +2 allocations. void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count) { // Allocate single buffer for our arrays - const int columns_bit_array_size = (int)ImBitArrayGetStorageSizeInBytes(columns_count); - ImSpanAllocator<6> span_allocator; + ImSpanAllocator<3> span_allocator; span_allocator.Reserve(0, columns_count * sizeof(ImGuiTableColumn)); span_allocator.Reserve(1, columns_count * sizeof(ImGuiTableColumnIdx)); span_allocator.Reserve(2, columns_count * sizeof(ImGuiTableCellData), 4); - for (int n = 3; n < 6; n++) - span_allocator.Reserve(n, columns_bit_array_size); table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes()); memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes()); span_allocator.SetArenaBasePtr(table->RawData); span_allocator.GetSpan(0, &table->Columns); span_allocator.GetSpan(1, &table->DisplayOrderToIndex); span_allocator.GetSpan(2, &table->RowCellData); - table->EnabledMaskByDisplayOrder = (ImU32*)span_allocator.GetSpanPtrBegin(3); - table->EnabledMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(4); - table->VisibleMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(5); } // Apply queued resizing/reordering/hiding requests void ImGui::TableBeginApplyRequests(ImGuiTable* table) { // Handle resizing request - // (We process this in the TableBegin() of the first instance of each table) + // (We process this at the first TableBegin of the frame) // FIXME-TABLE: Contains columns if our work area doesn't allow for scrolling? if (table->InstanceCurrent == 0) { @@ -659,7 +634,8 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table) table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder -= (ImGuiTableColumnIdx)reorder_dir; IM_ASSERT(dst_column->DisplayOrder == dst_order - reorder_dir); - // Display order is stored in both columns->IndexDisplayOrder and table->DisplayOrder[]. Rebuild later from the former. + // Display order is stored in both columns->IndexDisplayOrder and table->DisplayOrder[], + // rebuild the later from the former. for (int column_n = 0; column_n < table->ColumnsCount; column_n++) table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n; table->ReorderColumnDir = 0; @@ -733,8 +709,8 @@ static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, I } } -// Layout columns for the frame. This is in essence the followup to BeginTable() and this is our largest function. -// Runs on the first call to TableNextRow(), to give a chance for TableSetupColumn() and other TableSetupXXXXX() functions to be called first. +// Layout columns for the frame. This is in essence the followup to BeginTable(). +// Runs on the first call to TableNextRow(), to give a chance for TableSetupColumn() to be called first. // FIXME-TABLE: Our width (and therefore our WorkRect) will be minimal in the first frame for _WidthAuto columns. // Increase feedback side-effect with widgets relying on WorkRect.Max.x... Maybe provide a default distribution for _WidthAuto columns? void ImGui::TableUpdateLayout(ImGuiTable* table) @@ -745,8 +721,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_); table->IsDefaultDisplayOrder = true; table->ColumnsEnabledCount = 0; - ImBitArrayClearAllBits(table->EnabledMaskByIndex, table->ColumnsCount); - ImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, table->ColumnsCount); + table->EnabledMaskByIndex = 0x00; + table->EnabledMaskByDisplayOrder = 0x00; table->LeftMostEnabledColumn = -1; table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE @@ -811,8 +787,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) else table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n; column->IndexWithinEnabledSet = table->ColumnsEnabledCount++; - ImBitArraySetBit(table->EnabledMaskByIndex, column_n); - ImBitArraySetBit(table->EnabledMaskByDisplayOrder, column->DisplayOrder); + table->EnabledMaskByIndex |= (ImU64)1 << column_n; + table->EnabledMaskByDisplayOrder |= (ImU64)1 << column->DisplayOrder; prev_visible_column_idx = column_n; IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); @@ -855,12 +831,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) table->IsSettingsDirty = true; // [Part 3] Fix column flags and record a few extra information. - float sum_width_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns but including spacing/padding. - float stretch_sum_weights = 0.0f; // Sum of all weights for stretch columns. + float sum_width_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns but including spacing/padding. + float stretch_sum_weights = 0.0f; // Sum of all weights for stretch columns. table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) + if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n))) continue; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -876,7 +852,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) if (column->AutoFitQueue != 0x00) column->WidthRequest = width_auto; - else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && column->IsRequestOutput) + else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n))) column->WidthRequest = width_auto; // FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets @@ -917,14 +893,13 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // [Part 4] Apply final widths based on requested widths const ImRect work_rect = table->WorkRect; const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1); - const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synched tables with mismatching scrollbar state (#5920) - const float width_avail = ImMax(1.0f, (((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth()) - width_removed); + const float width_avail = ((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth(); const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests; float width_remaining_for_stretched_columns = width_avail_for_stretched_columns; table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) + if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n))) continue; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -951,7 +926,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths)) for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) { - if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) continue; ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]]; if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch)) @@ -967,14 +942,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // clear ActiveId, which is equivalent to the change provided by _AllowWhenBLockedByActiveItem). // - This allows columns to be marked as hovered when e.g. clicking a button inside the column, or using drag and drop. ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); - table_instance->HoveredRowLast = table_instance->HoveredRowNext; - table_instance->HoveredRowNext = -1; table->HoveredColumnBody = -1; table->HoveredColumnBorder = -1; const ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table_instance->LastOuterHeight)); const ImGuiID backup_active_id = g.ActiveId; g.ActiveId = 0; - const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0, ImGuiItemFlags_None); + const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0); g.ActiveId = backup_active_id; // [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column @@ -984,13 +957,14 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1; ImRect host_clip_rect = table->InnerClipRect; //host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2; - ImBitArrayClearAllBits(table->VisibleMaskByIndex, table->ColumnsCount); + table->VisibleMaskByIndex = 0x00; + table->RequestOutputMaskByIndex = 0x00; for (int order_n = 0; order_n < table->ColumnsCount; order_n++) { const int column_n = table->DisplayOrderToIndex[order_n]; ImGuiTableColumn* column = &table->Columns[column_n]; - column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); // Use Count NOT request so Header line changes layer when frozen + column->NavLayerCurrent = (ImS8)((table->FreezeRowsCount > 0 || column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); if (offset_x_frozen && table->FreezeColumnsCount == visible_n) { @@ -1001,7 +975,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Clear status flags column->Flags &= ~ImGuiTableColumnFlags_StatusMask_; - if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + if ((table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)) == 0) { // Hidden column: clear a few fields and we are done with it for the remainder of the function. // We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper. @@ -1054,10 +1028,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) column->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y); const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY; if (is_visible) - ImBitArraySetBit(table->VisibleMaskByIndex, column_n); + table->VisibleMaskByIndex |= ((ImU64)1 << column_n); // Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output. column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0; + if (column->IsRequestOutput) + table->RequestOutputMaskByIndex |= ((ImU64)1 << column_n); // Mark column as SkipItems (ignoring all items/layout) column->IsSkipItems = !column->IsEnabled || table->HostSkipItems; @@ -1126,14 +1102,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) table->BorderX1 = table->InnerClipRect.Min.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : -1.0f); table->BorderX2 = table->InnerClipRect.Max.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : +1.0f); - // Setup window's WorkRect.Max.y for GetContentRegionAvail(). Other values will be updated in each TableBeginCell() call. - float window_content_max_y; - if (table->Flags & ImGuiTableFlags_NoHostExtendY) - window_content_max_y = table->OuterRect.Max.y; - else - window_content_max_y = ImMax(table->InnerWindow->ContentRegionRect.Max.y, (table->Flags & ImGuiTableFlags_ScrollY) ? 0.0f : table->OuterRect.Max.y); - table->InnerWindow->WorkRect.Max.y = ImClamp(window_content_max_y - g.Style.CellPadding.y, table->InnerWindow->WorkRect.Min.y, table->InnerWindow->WorkRect.Max.y); - // [Part 9] Allocate draw channels and setup background cliprect TableSetupDrawChannels(table); @@ -1151,18 +1119,11 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) EndPopup(); } - // [Part 12] Sanitize and build sort specs before we have a chance to use them for display. + // [Part 13] Sanitize and build sort specs before we have a change to use them for display. // This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change) if (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable)) TableSortSpecsBuild(table); - // [Part 13] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns) - if (table->FreezeColumnsRequest > 0) - table->InnerWindow->DecoInnerSizeX1 = table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsRequest - 1]].MaxX - table->OuterRect.Min.x; - if (table->FreezeRowsRequest > 0) - table->InnerWindow->DecoInnerSizeY1 = table_instance->LastFrozenHeight; - table_instance->LastFrozenHeight = 0.0f; - // Initial state ImGuiWindow* inner_window = table->InnerWindow; if (table->Flags & ImGuiTableFlags_NoClip) @@ -1172,7 +1133,9 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) } // Process hit-testing on resizing borders. Actual size change will be applied in EndTable() -// - Set table->HoveredColumnBorder with a short delay/timer to reduce visual feedback noise. +// - Set table->HoveredColumnBorder with a short delay/timer to reduce feedback noise +// - Submit ahead of table contents and header, use ImGuiButtonFlags_AllowItemOverlap to prioritize widgets +// overlapping the same area. void ImGui::TableUpdateBorders(ImGuiTable* table) { ImGuiContext& g = *GImGui; @@ -1190,7 +1153,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table) for (int order_n = 0; order_n < table->ColumnsCount; order_n++) { - if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) continue; const int column_n = table->DisplayOrderToIndex[order_n]; @@ -1212,7 +1175,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table) //GetForegroundDrawList()->AddRect(hit_rect.Min, hit_rect.Max, IM_COL32(255, 0, 0, 100)); bool hovered = false, held = false; - bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_NoNavFocus); + bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_NoNavFocus); if (pressed && IsMouseDoubleClicked(0)) { TableSetColumnWidthAutoSingle(table, column_n); @@ -1326,7 +1289,7 @@ void ImGui::EndTable() float auto_fit_width_for_stretched = 0.0f; float auto_fit_width_for_stretched_min = 0.0f; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - if (IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) + if (table->EnabledMaskByIndex & ((ImU64)1 << column_n)) { ImGuiTableColumn* column = &table->Columns[column_n]; float column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column); @@ -1366,10 +1329,8 @@ void ImGui::EndTable() } // Pop from id stack - IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table_instance->TableInstanceID, "Mismatching PushID/PopID!"); + IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table->ID + table->InstanceCurrent, "Mismatching PushID/PopID!"); IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, "Too many PopItemWidth!"); - if (table->InstanceCurrent > 0) - PopID(); PopID(); // Restore window data that we modified @@ -1441,7 +1402,6 @@ void ImGui::EndTable() g.CurrentTable->DrawSplitter = &temp_data->DrawSplitter; } outer_window->DC.CurrentTableIdx = g.CurrentTable ? g.Tables.GetIndex(g.CurrentTable) : -1; - NavUpdateCurrentWindowIsScrollPushableX(); } // See "COLUMN SIZING POLICIES" comments at the top of this file @@ -1553,7 +1513,6 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows) // - TableGetCellBgRect() [Internal] // - TableGetColumnResizeID() [Internal] // - TableGetHoveredColumn() [Internal] -// - TableGetHoveredRow() [Internal] // - TableSetBgColor() //----------------------------------------------------------------------------- @@ -1641,14 +1600,14 @@ ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n) } // Return the resizing ID for the right-side of the given column. -ImGuiID ImGui::TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no) +ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no) { IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); - ImGuiID instance_id = TableGetInstanceID(table, instance_no); - return instance_id + 1 + column_n; // FIXME: #6140: still not ideal + ImGuiID id = table->ID + 1 + (instance_no * table->ColumnsCount) + column_n; + return id; } -// Return -1 when table is not hovered. return columns_count if hovering the unused space at the right of the right-most visible column. +// Return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. int ImGui::TableGetHoveredColumn() { ImGuiContext& g = *GImGui; @@ -1658,19 +1617,6 @@ int ImGui::TableGetHoveredColumn() return (int)table->HoveredColumnBody; } -// Return -1 when table is not hovered. Return maxrow+1 if in table but below last submitted row. -// *IMPORTANT* Unlike TableGetHoveredColumn(), this has a one frame latency in updating the value. -// This difference with is the reason why this is not public yet. -int ImGui::TableGetHoveredRow() -{ - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - if (!table) - return -1; - ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); - return (int)table_instance->HoveredRowLast; -} - void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n) { ImGuiContext& g = *GImGui; @@ -1689,7 +1635,7 @@ void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n return; if (column_n == -1) column_n = table->CurrentColumn; - if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n)) + if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) return; if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n) table->RowCellDataCurrent++; @@ -1822,10 +1768,6 @@ void ImGui::TableEndRow(ImGuiTable* table) const bool is_visible = (bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y); if (is_visible) { - // Update data for TableGetHoveredRow() - if (table->HoveredColumnBody != -1 && g.IO.MousePos.y >= bg_y1 && g.IO.MousePos.y < bg_y2) - TableGetInstanceData(table, table->InstanceCurrent)->HoveredRowNext = table->CurrentRow; - // Decide of background color for the row ImU32 bg_col0 = 0; ImU32 bg_col1 = 0; @@ -1897,15 +1839,17 @@ void ImGui::TableEndRow(ImGuiTable* table) // get the new cursor position. if (unfreeze_rows_request) for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main; + { + ImGuiTableColumn* column = &table->Columns[column_n]; + column->NavLayerCurrent = (ImS8)((column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); + } if (unfreeze_rows_actual) { IM_ASSERT(table->IsUnfrozenRows == false); - const float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y); table->IsUnfrozenRows = true; - TableGetInstanceData(table, table->InstanceCurrent)->LastFrozenHeight = y0 - table->OuterRect.Min.y; // BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect + float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y); table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y); table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y; table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen; @@ -1968,7 +1912,7 @@ bool ImGui::TableSetColumnIndex(int column_n) // Return whether the column is visible. User may choose to skip submitting items based on this return value, // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. - return table->Columns[column_n].IsRequestOutput; + return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; } // [Public] Append into the next column, wrap and create a new row when already on last column @@ -1993,7 +1937,8 @@ bool ImGui::TableNextColumn() // Return whether the column is visible. User may choose to skip submitting items based on this return value, // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. - return table->Columns[table->CurrentColumn].IsRequestOutput; + int column_n = table->CurrentColumn; + return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; } @@ -2002,7 +1947,6 @@ bool ImGui::TableNextColumn() // FIXME-TABLE FIXME-OPT: Could probably shortcut some things for non-active or clipped columns. void ImGui::TableBeginCell(ImGuiTable* table, int column_n) { - ImGuiContext& g = *GImGui; ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiWindow* window = table->InnerWindow; table->CurrentColumn = column_n; @@ -2019,15 +1963,19 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n) window->DC.CurrLineTextBaseOffset = table->RowTextBaseline; window->DC.NavLayerCurrent = (ImGuiNavLayer)column->NavLayerCurrent; - // Note how WorkRect.Max.y is only set once during layout window->WorkRect.Min.y = window->DC.CursorPos.y; window->WorkRect.Min.x = column->WorkMinX; window->WorkRect.Max.x = column->WorkMaxX; window->DC.ItemWidth = column->ItemWidth; + // To allow ImGuiListClipper to function we propagate our row height + if (!column->IsEnabled) + window->DC.CursorPos.y = ImMax(window->DC.CursorPos.y, table->RowPosY2); + window->SkipItems = column->IsSkipItems; if (column->IsSkipItems) { + ImGuiContext& g = *GImGui; g.LastItemData.ID = 0; g.LastItemData.StatusFlags = 0; } @@ -2046,6 +1994,7 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n) } // Logging + ImGuiContext& g = *GImGui; if (g.LogEnabled && !column->IsSkipItems) { LogRenderedText(&window->DC.CursorPos, "|"); @@ -2069,8 +2018,7 @@ void ImGui::TableEndCell(ImGuiTable* table) else p_max_pos_x = table->IsUnfrozenRows ? &column->ContentMaxXUnfrozen : &column->ContentMaxXFrozen; *p_max_pos_x = ImMax(*p_max_pos_x, window->DC.CursorMaxPos.x); - if (column->IsEnabled) - table->RowPosY2 = ImMax(table->RowPosY2, window->DC.CursorMaxPos.y + table->CellPaddingY); + table->RowPosY2 = ImMax(table->RowPosY2, window->DC.CursorMaxPos.y + table->CellPaddingY); column->ItemWidth = window->DC.ItemWidth; // Propagate text baseline for the entire row @@ -2165,7 +2113,7 @@ void ImGui::TableSetColumnWidth(int column_n, float width) // - All stretch: easy. // - One or more fixed + one stretch: easy. // - One or more fixed + more than one stretch: tricky. - // Qt when manual resize is enabled only supports a single _trailing_ stretch column, we support more cases here. + // Qt when manual resize is enabled only support a single _trailing_ stretch column. // When forwarding resize from Wn| to Fn+1| we need to be considerate of the _NoResize flag on Fn+1. // FIXME-TABLE: Find a way to rewrite all of this so interactions feel more consistent for the user. @@ -2248,7 +2196,7 @@ void ImGui::TableUpdateColumnsWeightFromWidth(ImGuiTable* table) { IM_ASSERT(table->LeftMostStretchedColumn != -1 && table->RightMostStretchedColumn != -1); - // Measure existing quantities + // Measure existing quantity float visible_weight = 0.0f; float visible_width = 0.0f; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) @@ -2330,7 +2278,7 @@ void ImGui::TableSetupDrawChannels(ImGuiTable* table) const int freeze_row_multiplier = (table->FreezeRowsCount > 0) ? 2 : 1; const int channels_for_row = (table->Flags & ImGuiTableFlags_NoClip) ? 1 : table->ColumnsEnabledCount; const int channels_for_bg = 1 + 1 * freeze_row_multiplier; - const int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || (memcmp(table->VisibleMaskByIndex, table->EnabledMaskByIndex, ImBitArrayGetStorageSizeInBytes(table->ColumnsCount)) != 0)) ? +1 : 0; + const int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || table->VisibleMaskByIndex != table->EnabledMaskByIndex) ? +1 : 0; const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy; table->DrawSplitter->Split(table->InnerWindow->DrawList, channels_total); table->DummyDrawChannel = (ImGuiTableDrawChannelIdx)((channels_for_dummy > 0) ? channels_total - 1 : -1); @@ -2404,26 +2352,19 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) // Track which groups we are going to attempt to merge, and which channels goes into each group. struct MergeGroup { - ImRect ClipRect; - int ChannelsCount = 0; - ImBitArrayPtr ChannelsMask = NULL; + ImRect ClipRect; + int ChannelsCount; + ImBitArray ChannelsMask; + + MergeGroup() { ChannelsCount = 0; } }; int merge_group_mask = 0x00; MergeGroup merge_groups[4]; - // Use a reusable temp buffer for the merge masks as they are dynamically sized. - const int max_draw_channels = (4 + table->ColumnsCount * 2); - const int size_for_masks_bitarrays_one = (int)ImBitArrayGetStorageSizeInBytes(max_draw_channels); - g.TempBuffer.reserve(size_for_masks_bitarrays_one * 5); - memset(g.TempBuffer.Data, 0, size_for_masks_bitarrays_one * 5); - for (int n = 0; n < IM_ARRAYSIZE(merge_groups); n++) - merge_groups[n].ChannelsMask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * n)); - ImBitArrayPtr remaining_mask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * 4)); - // 1. Scan channels and take note of those which can be merged for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n)) + if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) continue; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -2455,11 +2396,11 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) } const int merge_group_n = (has_freeze_h && column_n < table->FreezeColumnsCount ? 0 : 1) + (has_freeze_v && merge_group_sub_n == 0 ? 0 : 2); - IM_ASSERT(channel_no < max_draw_channels); + IM_ASSERT(channel_no < IMGUI_TABLE_MAX_DRAW_CHANNELS); MergeGroup* merge_group = &merge_groups[merge_group_n]; if (merge_group->ChannelsCount == 0) merge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX); - ImBitArraySetBit(merge_group->ChannelsMask, channel_no); + merge_group->ChannelsMask.SetBit(channel_no); merge_group->ChannelsCount++; merge_group->ClipRect.Add(src_channel->_CmdBuffer[0].ClipRect); merge_group_mask |= (1 << merge_group_n); @@ -2495,8 +2436,9 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) const int LEADING_DRAW_CHANNELS = 2; g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data; - ImBitArraySetBitRange(remaining_mask, LEADING_DRAW_CHANNELS, splitter->_Count); - ImBitArrayClearBit(remaining_mask, table->Bg2DrawChannelUnfrozen); + ImBitArray remaining_mask; // We need 132-bit of storage + remaining_mask.SetBitRange(LEADING_DRAW_CHANNELS, splitter->_Count); + remaining_mask.ClearBit(table->Bg2DrawChannelUnfrozen); IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN); int remaining_count = splitter->_Count - (has_freeze_v ? LEADING_DRAW_CHANNELS + 1 : LEADING_DRAW_CHANNELS); //ImRect host_rect = (table->InnerWindow == table->OuterWindow) ? table->InnerClipRect : table->HostClipRect; @@ -2523,18 +2465,20 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) merge_clip_rect.Max.x = ImMax(merge_clip_rect.Max.x, host_rect.Max.x); if ((merge_group_n & 2) != 0 && (table->Flags & ImGuiTableFlags_NoHostExtendY) == 0) merge_clip_rect.Max.y = ImMax(merge_clip_rect.Max.y, host_rect.Max.y); - //GetForegroundDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 0, 0, 200), 0.0f, 0, 1.0f); // [DEBUG] - //GetForegroundDrawList()->AddLine(merge_group->ClipRect.Min, merge_clip_rect.Min, IM_COL32(255, 100, 0, 200)); - //GetForegroundDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200)); +#if 0 + GetOverlayDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 0, 0, 200), 0.0f, 0, 1.0f); + GetOverlayDrawList()->AddLine(merge_group->ClipRect.Min, merge_clip_rect.Min, IM_COL32(255, 100, 0, 200)); + GetOverlayDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200)); +#endif remaining_count -= merge_group->ChannelsCount; - for (int n = 0; n < (size_for_masks_bitarrays_one >> 2); n++) - remaining_mask[n] &= ~merge_group->ChannelsMask[n]; + for (int n = 0; n < IM_ARRAYSIZE(remaining_mask.Storage); n++) + remaining_mask.Storage[n] &= ~merge_group->ChannelsMask.Storage[n]; for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++) { // Copy + overwrite new clip rect - if (!IM_BITARRAY_TESTBIT(merge_group->ChannelsMask, n)) + if (!merge_group->ChannelsMask.TestBit(n)) continue; - IM_BITARRAY_CLEARBIT(merge_group->ChannelsMask, n); + merge_group->ChannelsMask.ClearBit(n); merge_channels_count--; ImDrawChannel* channel = &splitter->_Channels[n]; @@ -2552,7 +2496,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) // Append unmergeable channels that we didn't reorder at the end of the list for (int n = 0; n < splitter->_Count && remaining_count != 0; n++) { - if (!IM_BITARRAY_TESTBIT(remaining_mask, n)) + if (!remaining_mask.TestBit(n)) continue; ImDrawChannel* channel = &splitter->_Channels[n]; memcpy(dst_tmp++, channel, sizeof(ImDrawChannel)); @@ -2584,7 +2528,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) { for (int order_n = 0; order_n < table->ColumnsCount; order_n++) { - if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) continue; const int column_n = table->DisplayOrderToIndex[order_n]; @@ -2689,6 +2633,7 @@ ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() TableUpdateLayout(table); TableSortSpecsBuild(table); + return &table->SortSpecs; } @@ -2807,7 +2752,7 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table) } } - // Fallback default sort order (if no column with the ImGuiTableColumnFlags_DefaultSort flag) + // Fallback default sort order (if no column had the ImGuiTableColumnFlags_DefaultSort flag) if (sort_order_count == 0 && !(table->Flags & ImGuiTableFlags_SortTristate)) for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { @@ -2911,9 +2856,10 @@ void ImGui::TableHeadersRow() continue; // Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them) - // In your own code you may omit the PushID/PopID all-together, provided you know they won't collide. + // - in your own code you may omit the PushID/PopID all-together, provided you know they won't collide + // - table->InstanceCurrent is only >0 when we use multiple BeginTable/EndTable calls with same identifier. const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n); - PushID(column_n); + PushID(table->InstanceCurrent * table->ColumnsCount + column_n); TableHeader(name); PopID(); } @@ -2984,9 +2930,11 @@ void ImGui::TableHeader(const char* label) //GetForegroundDrawList()->AddRect(cell_r.Min, cell_r.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] //GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] - // Using AllowOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items. + // Using AllowItemOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items. bool hovered, held; - bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowOverlap); + bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowItemOverlap); + if (g.ActiveId != id) + SetItemAllowOverlap(); if (held || hovered || selected) { const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); @@ -3026,7 +2974,7 @@ void ImGui::TableHeader(const char* label) } // Sort order arrow - const float ellipsis_max = ImMax(cell_r.Max.x - w_arrow - w_sort_text, label_pos.x); + const float ellipsis_max = cell_r.Max.x - w_arrow - w_sort_text; if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort)) { if (column->SortOrder != -1) @@ -3057,8 +3005,8 @@ void ImGui::TableHeader(const char* label) RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, ellipsis_max, label, label_end, &label_size); const bool text_clipped = label_size.x > (ellipsis_max - label_pos.x); - if (text_clipped && hovered && g.ActiveId == 0) - SetItemTooltip("%.*s", (int)(label_end - label), label); + if (text_clipped && hovered && g.ActiveId == 0 && IsItemHovered(ImGuiHoveredFlags_DelayNormal)) + SetTooltip("%.*s", (int)(label_end - label), label); // We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden if (IsMouseReleased(1) && IsItemHovered()) @@ -3496,12 +3444,12 @@ static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandle if (!save_column) continue; buf->appendf("Column %-2d", column_n); - if (column->UserID != 0) { buf->appendf(" UserID=%08X", column->UserID); } - if (save_size && column->IsStretch) { buf->appendf(" Weight=%.4f", column->WidthOrWeight); } - if (save_size && !column->IsStretch) { buf->appendf(" Width=%d", (int)column->WidthOrWeight); } - if (save_visible) { buf->appendf(" Visible=%d", column->IsEnabled); } - if (save_order) { buf->appendf(" Order=%d", column->DisplayOrder); } - if (save_sort && column->SortOrder != -1) { buf->appendf(" Sort=%d%c", column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? 'v' : '^'); } + if (column->UserID != 0) buf->appendf(" UserID=%08X", column->UserID); + if (save_size && column->IsStretch) buf->appendf(" Weight=%.4f", column->WidthOrWeight); + if (save_size && !column->IsStretch) buf->appendf(" Width=%d", (int)column->WidthOrWeight); + if (save_visible) buf->appendf(" Visible=%d", column->IsEnabled); + if (save_order) buf->appendf(" Order=%d", column->DisplayOrder); + if (save_sort && column->SortOrder != -1) buf->appendf(" Sort=%d%c", column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? 'v' : '^'); buf->append("\n"); } buf->append("\n"); @@ -3549,7 +3497,7 @@ void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table) IM_ASSERT(table->MemoryCompacted == false); table->SortSpecs.Specs = NULL; table->SortSpecsMulti.clear(); - table->IsSortSpecsDirty = true; // FIXME: In theory shouldn't have to leak into user performing a sort on resume. + table->IsSortSpecsDirty = true; // FIXME: shouldn't have to leak into user performing a sort table->ColumnsNames.clear(); table->MemoryCompacted = true; for (int n = 0; n < table->ColumnsCount; n++) @@ -3602,9 +3550,13 @@ static const char* DebugNodeTableGetSizingPolicyDesc(ImGuiTableFlags sizing_poli void ImGui::DebugNodeTable(ImGuiTable* table) { - const bool is_active = (table->LastFrameActive >= GetFrameCount() - 2); // Note that fully clipped early out scrolling tables will appear as inactive here. + char buf[512]; + char* p = buf; + const char* buf_end = buf + IM_ARRAYSIZE(buf); + const bool is_active = (table->LastFrameActive >= ImGui::GetFrameCount() - 2); // Note that fully clipped early out scrolling tables will appear as inactive here. + ImFormatString(p, buf_end - p, "Table 0x%08X (%d columns, in '%s')%s", table->ID, table->ColumnsCount, table->OuterWindow->Name, is_active ? "" : " *Inactive*"); if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } - bool open = TreeNode(table, "Table 0x%08X (%d columns, in '%s')%s", table->ID, table->ColumnsCount, table->OuterWindow->Name, is_active ? "" : " *Inactive*"); + bool open = TreeNode(table, "%s", buf); if (!is_active) { PopStyleColor(); } if (IsItemHovered()) GetForegroundDrawList()->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255)); @@ -3613,18 +3565,13 @@ void ImGui::DebugNodeTable(ImGuiTable* table) if (!open) return; if (table->InstanceCurrent > 0) - Text("** %d instances of same table! Some data below will refer to last instance.", table->InstanceCurrent + 1); + ImGui::Text("** %d instances of same table! Some data below will refer to last instance.", table->InstanceCurrent + 1); bool clear_settings = SmallButton("Clear settings"); BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f) Sizing: '%s'", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight(), DebugNodeTableGetSizingPolicyDesc(table->Flags)); BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : ""); BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX); BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder); BulletText("ResizedColumn: %d, ReorderColumn: %d, HeldHeaderColumn: %d", table->ResizedColumn, table->ReorderColumn, table->HeldHeaderColumn); - for (int n = 0; n < table->InstanceCurrent + 1; n++) - { - ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, n); - BulletText("Instance %d: HoveredRow: %d, LastOuterHeight: %.2f", n, table_instance->HoveredRowLast, table_instance->LastOuterHeight); - } //BulletText("BgDrawChannels: %d/%d", 0, table->BgDrawChannelUnfrozen); float sum_weights = 0.0f; for (int n = 0; n < table->ColumnsCount; n++) @@ -3634,7 +3581,6 @@ void ImGui::DebugNodeTable(ImGuiTable* table) { ImGuiTableColumn* column = &table->Columns[n]; const char* name = TableGetColumnName(table, n); - char buf[512]; ImFormatString(buf, IM_ARRAYSIZE(buf), "Column %d order %d '%s': offset %+.2f to %+.2f%s\n" "Enabled: %d, VisibleX/Y: %d/%d, RequestOutput: %d, SkipItems: %d, DrawChannels: %d,%d\n" @@ -3923,7 +3869,6 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiOldColumnFl columns->Count = columns_count; columns->Flags = flags; window->DC.CurrentColumns = columns; - window->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX(); columns->HostCursorPosY = window->DC.CursorPos.y; columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; @@ -3983,7 +3928,6 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiOldColumnFl window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; - window->WorkRect.Max.y = window->ContentRegionRect.Max.y; } void ImGui::NextColumn() @@ -4115,7 +4059,6 @@ void ImGui::EndColumns() window->DC.CurrentColumns = NULL; window->DC.ColumnsOffset.x = 0.0f; window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); - NavUpdateCurrentWindowIsScrollPushableX(); } void ImGui::Columns(int columns_count, const char* id, bool border) diff --git a/3rdparty/bgfx/3rdparty/dear-imgui/imgui_widgets.cpp b/3rdparty/bgfx/3rdparty/dear-imgui/imgui_widgets.cpp index c611d312c2f..3b8be01e7d4 100644 --- a/3rdparty/bgfx/3rdparty/dear-imgui/imgui_widgets.cpp +++ b/3rdparty/bgfx/3rdparty/dear-imgui/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.8 WIP +// dear imgui, v1.89.1 WIP // (widgets code) /* @@ -32,16 +32,20 @@ Index of this file: #define _CRT_SECURE_NO_WARNINGS #endif +#include "imgui.h" +#ifndef IMGUI_DISABLE + #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif - -#include "imgui.h" -#ifndef IMGUI_DISABLE #include "imgui_internal.h" // System includes +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else #include // intptr_t +#endif //------------------------------------------------------------------------- // Warnings @@ -122,7 +126,7 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); // For InputTextEx() static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source); static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); -static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); +static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); //------------------------------------------------------------------------- // [SECTION] Widgets: Text, etc. @@ -270,6 +274,7 @@ void ImGui::TextV(const char* fmt, va_list args) if (window->SkipItems) return; + // FIXME-OPT: Handle the %s shortcut? const char* text, *text_end; ImFormatStringToTempBufferV(&text, &text_end, fmt, args); TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); @@ -286,7 +291,10 @@ void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args) { PushStyleColor(ImGuiCol_Text, col); - TextV(fmt, args); + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting + else + TextV(fmt, args); PopStyleColor(); } @@ -302,7 +310,10 @@ void ImGui::TextDisabledV(const char* fmt, va_list args) { ImGuiContext& g = *GImGui; PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); - TextV(fmt, args); + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting + else + TextV(fmt, args); PopStyleColor(); } @@ -317,10 +328,13 @@ void ImGui::TextWrapped(const char* fmt, ...) void ImGui::TextWrappedV(const char* fmt, va_list args) { ImGuiContext& g = *GImGui; - const bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set if (need_backup) PushTextWrapPos(0.0f); - TextV(fmt, args); + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting + else + TextV(fmt, args); if (need_backup) PopTextWrapPos(); } @@ -488,27 +502,22 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0) flags |= ImGuiButtonFlags_PressedOnDefault_; - // Default behavior inherited from item flags - // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that. - ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); - if (flags & ImGuiButtonFlags_AllowOverlap) - item_flags |= ImGuiItemflags_AllowOverlap; - if (flags & ImGuiButtonFlags_Repeat) - item_flags |= ImGuiItemFlags_ButtonRepeat; - ImGuiWindow* backup_hovered_window = g.HoveredWindow; const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window; if (flatten_hovered_children) g.HoveredWindow = window; #ifdef IMGUI_ENABLE_TEST_ENGINE - // Alternate registration spot, for when caller didn't use ItemAdd() if (id != 0 && g.LastItemData.ID != id) - IMGUI_TEST_ENGINE_ITEM_ADD(id, bb, NULL); + IMGUI_TEST_ENGINE_ITEM_ADD(bb, id); #endif bool pressed = false; - bool hovered = ItemHoverable(bb, id, item_flags); + bool hovered = ItemHoverable(bb, id); + + // Drag source doesn't report as hovered + if (hovered && g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover)) + hovered = false; // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) @@ -527,25 +536,21 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (flatten_hovered_children) g.HoveredWindow = backup_hovered_window; + // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. + if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0)) + hovered = false; + // Mouse handling const ImGuiID test_owner_id = (flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any : id; if (hovered) { - // Poll mouse buttons - // - 'mouse_button_clicked' is generally carried into ActiveIdMouseButton when setting ActiveId. - // - Technically we only need some values in one code path, but since this is gated by hovered test this is fine. - int mouse_button_clicked = -1; - int mouse_button_released = -1; - for (int button = 0; button < 3; button++) - if (flags & (ImGuiButtonFlags_MouseButtonLeft << button)) // Handle ImGuiButtonFlags_MouseButtonRight and ImGuiButtonFlags_MouseButtonMiddle here. - { - if (IsMouseClicked(button, test_owner_id) && mouse_button_clicked == -1) { mouse_button_clicked = button; } - if (IsMouseReleased(button, test_owner_id) && mouse_button_released == -1) { mouse_button_released = button; } - } - - // Process initial action if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) { + // Poll buttons + int mouse_button_clicked = -1; + if ((flags & ImGuiButtonFlags_MouseButtonLeft) && IsMouseClicked(0, test_owner_id)) { mouse_button_clicked = 0; } + else if ((flags & ImGuiButtonFlags_MouseButtonRight) && IsMouseClicked(1, test_owner_id)) { mouse_button_clicked = 1; } + else if ((flags & ImGuiButtonFlags_MouseButtonMiddle) && IsMouseClicked(2, test_owner_id)) { mouse_button_clicked = 2; } if (mouse_button_clicked != -1 && g.ActiveId != id) { if (!(flags & ImGuiButtonFlags_NoSetKeyOwner)) @@ -573,9 +578,13 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } if (flags & ImGuiButtonFlags_PressedOnRelease) { + int mouse_button_released = -1; + if ((flags & ImGuiButtonFlags_MouseButtonLeft) && IsMouseReleased(0, test_owner_id)) { mouse_button_released = 0; } + else if ((flags & ImGuiButtonFlags_MouseButtonRight) && IsMouseReleased(1, test_owner_id)) { mouse_button_released = 1; } + else if ((flags & ImGuiButtonFlags_MouseButtonMiddle) && IsMouseReleased(2, test_owner_id)) { mouse_button_released = 2; } if (mouse_button_released != -1) { - const bool has_repeated_at_least_once = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior + const bool has_repeated_at_least_once = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior if (!has_repeated_at_least_once) pressed = true; if (!(flags & ImGuiButtonFlags_NoNavFocus)) @@ -586,7 +595,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. - if (g.ActiveId == id && (item_flags & ImGuiItemFlags_ButtonRepeat)) + if (g.ActiveId == id && (flags & ImGuiButtonFlags_Repeat)) if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, test_owner_id, ImGuiInputFlags_Repeat)) pressed = true; } @@ -604,13 +613,12 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { bool nav_activated_by_code = (g.NavActivateId == id); bool nav_activated_by_inputs = (g.NavActivatePressedId == id); - if (!nav_activated_by_inputs && (item_flags & ImGuiItemFlags_ButtonRepeat)) + if (!nav_activated_by_inputs && (flags & ImGuiButtonFlags_Repeat)) { - // Avoid pressing multiple keys from triggering excessive amount of repeat events + // Avoid pressing both keys from triggering double amount of repeat events const ImGuiKeyData* key1 = GetKeyData(ImGuiKey_Space); - const ImGuiKeyData* key2 = GetKeyData(ImGuiKey_Enter); - const ImGuiKeyData* key3 = GetKeyData(ImGuiKey_NavGamepadActivate); - const float t1 = ImMax(ImMax(key1->DownDuration, key2->DownDuration), key3->DownDuration); + const ImGuiKeyData* key2 = GetKeyData(ImGuiKey_NavGamepadActivate); + const float t1 = ImMax(key1->DownDuration, key2->DownDuration); nav_activated_by_inputs = CalcTypematicRepeatAmount(t1 - g.IO.DeltaTime, t1, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; } if (nav_activated_by_code || nav_activated_by_inputs) @@ -618,7 +626,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button. pressed = true; SetActiveID(id, window); - g.ActiveIdSource = g.NavInputSource; + g.ActiveIdSource = ImGuiInputSource_Nav; if (!(flags & ImGuiButtonFlags_NoNavFocus)) SetFocusID(id, window); } @@ -634,12 +642,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool g.ActiveIdClickOffset = g.IO.MousePos - bb.Min; const int mouse_button = g.ActiveIdMouseButton; - if (mouse_button == -1) - { - // Fallback for the rare situation were g.ActiveId was set programmatically or from another widget (e.g. #6304). - ClearActiveID(); - } - else if (IsMouseDown(mouse_button, test_owner_id)) + if (IsMouseDown(mouse_button, test_owner_id)) { held = true; } @@ -651,7 +654,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { // Report as pressed when releasing the mouse (this is the most common path) bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseReleased[mouse_button] && g.IO.MouseClickedLastCount[mouse_button] == 2; - bool is_repeating_already = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps + bool is_repeating_already = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps bool is_button_avail_or_owned = TestKeyOwner(MouseButtonToKey(mouse_button), test_owner_id); if (!is_double_click_release && !is_repeating_already && is_button_avail_or_owned) pressed = true; @@ -661,7 +664,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (!(flags & ImGuiButtonFlags_NoNavFocus)) g.NavDisableHighlight = true; } - else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) + else if (g.ActiveIdSource == ImGuiInputSource_Nav) { // When activated using Nav, we hold on the ActiveID until activation button is released if (g.NavActivateDownId != id) @@ -698,6 +701,9 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags if (!ItemAdd(bb, id)) return false; + if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); @@ -774,6 +780,9 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu if (!ItemAdd(bb, id)) return false; + if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); @@ -822,7 +831,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) ImU32 col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered); ImVec2 center = bb.GetCenter(); if (hovered) - window->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col); + window->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col, 12); float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; ImU32 cross_col = GetColorU32(ImGuiCol_Text); @@ -847,7 +856,7 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); ImU32 text_col = GetColorU32(ImGuiCol_Text); if (hovered || held) - window->DrawList->AddCircleFilled(bb.GetCenter()/*+ ImVec2(0.0f, -0.5f)*/, g.FontSize * 0.5f + 1.0f, bg_col); + window->DrawList->AddCircleFilled(bb.GetCenter()/*+ ImVec2(0.0f, -0.5f)*/, g.FontSize * 0.5f + 1.0f, bg_col, 12); RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); // Switch to moving the window after mouse is moved beyond the initial drag threshold @@ -871,9 +880,9 @@ ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) IM_ASSERT(scrollbar_size > 0.0f); if (axis == ImGuiAxis_X) - return ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size); + return ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x, outer_rect.Max.y); else - return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size); + return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x, inner_rect.Max.y); } void ImGui::Scrollbar(ImGuiAxis axis) @@ -1029,7 +1038,7 @@ void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& // ImageButton() is flawed as 'id' is always derived from 'texture_id' (see #2464 #1390) // We provide this internal helper to write your own variant while we figure out how to redesign the public ImageButton() API. -bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) +bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -1043,7 +1052,7 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size return false; bool hovered, held; - bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + bool pressed = ButtonBehavior(bb, id, &hovered, &held); // Render const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); @@ -1158,8 +1167,10 @@ bool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value) if (!all_on && any_on) { ImGuiContext& g = *GImGui; - g.NextItemData.ItemFlags |= ImGuiItemFlags_MixedValue; + ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_MixedValue; pressed = Checkbox(label, &all_on); + g.CurrentItemFlags = backup_item_flags; } else { @@ -1226,18 +1237,17 @@ bool ImGui::RadioButton(const char* label, bool active) MarkItemEdited(id); RenderNavHighlight(total_bb, id); - const int num_segment = window->DrawList->_CalcCircleAutoSegmentCount(radius); - window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), num_segment); + window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16); if (active) { const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); - window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark)); + window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16); } if (style.FrameBorderSize > 0.0f) { - window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), num_segment, style.FrameBorderSize); - window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), num_segment, style.FrameBorderSize); + window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize); + window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize); } ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); @@ -1380,9 +1390,7 @@ void ImGui::AlignTextToFramePadding() } // Horizontal/vertical separating line -// FIXME: Surprisingly, this seemingly trivial widget is a victim of many different legacy/tricky layout issues. -// Note how thickness == 1.0f is handled specifically as not moving CursorPos by 'thickness', but other values are. -void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) +void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -1390,20 +1398,21 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) ImGuiContext& g = *GImGui; IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected - IM_ASSERT(thickness > 0.0f); + float thickness_draw = 1.0f; + float thickness_layout = 0.0f; if (flags & ImGuiSeparatorFlags_Vertical) { - // Vertical separator, for menu bars (use current line height). + // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. float y1 = window->DC.CursorPos.y; float y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y; - const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness, y2)); - ItemSize(ImVec2(thickness, 0.0f)); + const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness_draw, y2)); + ItemSize(ImVec2(thickness_layout, 0.0f)); if (!ItemAdd(bb, 0)) return; // Draw - window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator)); + window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator)); if (g.LogEnabled) LogText(" |"); } @@ -1425,22 +1434,19 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) x2 = table->Columns[table->CurrentColumn].MaxX; } - // Before Tables API happened, we relied on Separator() to span all columns of a Columns() set. - // We currently don't need to provide the same feature for tables because tables naturally have border features. ImGuiOldColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL; if (columns) PushColumnsBackground(); // We don't provide our width to the layout so that it doesn't get feed back into AutoFit // FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell) - const float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change. - const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness)); - ItemSize(ImVec2(0.0f, thickness_for_layout)); - - if (ItemAdd(bb, 0)) + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness_draw)); + ItemSize(ImVec2(0.0f, thickness_layout)); + const bool item_visible = ItemAdd(bb, 0); + if (item_visible) { // Draw - window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator)); + window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator)); if (g.LogEnabled) LogRenderedText(&bb.Min, "--------------------------------\n"); @@ -1460,80 +1466,14 @@ void ImGui::Separator() if (window->SkipItems) return; - // Those flags should eventually be configurable by the user - // FIXME: We cannot g.Style.SeparatorTextBorderSize for thickness as it relates to SeparatorText() which is a decorated separator, not defaulting to 1.0f. + // Those flags should eventually be overridable by the user ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; flags |= ImGuiSeparatorFlags_SpanAllColumns; // NB: this only applies to legacy Columns() api as they relied on Separator() a lot. - SeparatorEx(flags, 1.0f); -} - -void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiStyle& style = g.Style; - - const ImVec2 label_size = CalcTextSize(label, label_end, false); - const ImVec2 pos = window->DC.CursorPos; - const ImVec2 padding = style.SeparatorTextPadding; - - const float separator_thickness = style.SeparatorTextBorderSize; - const ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, ImMax(label_size.y + padding.y * 2.0f, separator_thickness)); - const ImRect bb(pos, ImVec2(window->WorkRect.Max.x, pos.y + min_size.y)); - const float text_baseline_y = ImFloor((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.99999f); //ImMax(padding.y, ImFloor((style.SeparatorTextSize - label_size.y) * 0.5f)); - ItemSize(min_size, text_baseline_y); - if (!ItemAdd(bb, id)) - return; - - const float sep1_x1 = pos.x; - const float sep2_x2 = bb.Max.x; - const float seps_y = ImFloor((bb.Min.y + bb.Max.y) * 0.5f + 0.99999f); - - const float label_avail_w = ImMax(0.0f, sep2_x2 - sep1_x1 - padding.x * 2.0f); - const ImVec2 label_pos(pos.x + padding.x + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y); // FIXME-ALIGN - - // This allows using SameLine() to position something in the 'extra_w' - window->DC.CursorPosPrevLine.x = label_pos.x + label_size.x; - - const ImU32 separator_col = GetColorU32(ImGuiCol_Separator); - if (label_size.x > 0.0f) - { - const float sep1_x2 = label_pos.x - style.ItemSpacing.x; - const float sep2_x1 = label_pos.x + label_size.x + extra_w + style.ItemSpacing.x; - if (sep1_x2 > sep1_x1 && separator_thickness > 0.0f) - window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep1_x2, seps_y), separator_col, separator_thickness); - if (sep2_x2 > sep2_x1 && separator_thickness > 0.0f) - window->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); - if (g.LogEnabled) - LogSetNextTextDecoration("---", NULL); - RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, bb.Max.x, label, label_end, &label_size); - } - else - { - if (g.LogEnabled) - LogText("---"); - if (separator_thickness > 0.0f) - window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); - } -} - -void ImGui::SeparatorText(const char* label) -{ - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return; - - // The SeparatorText() vs SeparatorTextEx() distinction is designed to be considerate that we may want: - // - allow separator-text to be draggable items (would require a stable ID + a noticeable highlight) - // - this high-level entry point to allow formatting? (which in turns may require ID separate from formatted string) - // - because of this we probably can't turn 'const char* label' into 'const char* fmt, ...' - // Otherwise, we can decide that users wanting to drag this would layout a dedicated drag-item, - // and then we can turn this into a format function. - SeparatorTextEx(0, label, FindRenderedTextEnd(label), 0.0f); + SeparatorEx(flags); } // Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise. -bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay, ImU32 bg_col) +bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -1541,20 +1481,14 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float if (!ItemAdd(bb, id, NULL, ImGuiItemFlags_NoNav)) return false; - // FIXME: AFAIK the only leftover reason for passing ImGuiButtonFlags_AllowOverlap here is - // to allow caller of SplitterBehavior() to call SetItemAllowOverlap() after the item. - // Nowadays we would instead want to use SetNextItemAllowOverlap() before the item. - ImGuiButtonFlags button_flags = ImGuiButtonFlags_FlattenChildren; -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - button_flags |= ImGuiButtonFlags_AllowOverlap; -#endif - bool hovered, held; ImRect bb_interact = bb; bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); - ButtonBehavior(bb_interact, id, &hovered, &held, button_flags); + ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap); if (hovered) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb + if (g.ActiveId != id) + SetItemAllowOverlap(); if (held || (hovered && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay)) SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW); @@ -1587,9 +1521,7 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float } } - // Render at new position - if (bg_col & IM_COL32_A_MASK) - window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, bg_col, 0.0f); + // Render const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : (hovered && g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, 0.0f); @@ -1767,12 +1699,7 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8; else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4; else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20; - ImVec2 constraint_min(0.0f, 0.0f), constraint_max(FLT_MAX, FLT_MAX); - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size - constraint_min.x = w; - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f) - constraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items); - SetNextWindowSizeConstraints(constraint_min, constraint_max); + SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); } // This is essentially a specialized version of BeginPopupEx() @@ -1823,7 +1750,7 @@ bool ImGui::BeginComboPreview() if (window->SkipItems || !(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)) return false; IM_ASSERT(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag? - if (!window->ClipRect.Overlaps(preview_data->PreviewRect)) // Narrower test (optional) + if (!window->ClipRect.Contains(preview_data->PreviewRect)) // Narrower test (optional) return false; // FIXME: This could be contained in a PushWorkRect() api @@ -1922,7 +1849,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi const char* item_text; if (!items_getter(data, i, &item_text)) item_text = "*Unknown item*"; - if (Selectable(item_text, item_selected) && *current_item != i) + if (Selectable(item_text, item_selected)) { value_changed = true; *current_item = i; @@ -2088,8 +2015,7 @@ bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void memcpy(&data_backup, p_data, type_info->Size); // Sanitize format - // - For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf - // - In theory could treat empty format as using default, but this would only cover rare/bizarre case of using InputScalar() + integer + format string without %. + // For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf char format_sanitized[32]; if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) format = type_info->ScanFmt; @@ -2250,7 +2176,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (g.IO.KeyShift) adjust_delta *= 10.0f; } - else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) + else if (g.ActiveIdSource == ImGuiInputSource_Nav) { const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow); @@ -2357,7 +2283,7 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v // Those are the things we can do easily outside the DragBehaviorT<> template, saves code generation. if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) ClearActiveID(); - else if ((g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) ClearActiveID(); } if (g.ActiveId != id) @@ -2409,7 +2335,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + const bool hovered = ItemHoverable(frame_bb, id); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { @@ -2417,18 +2343,18 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; const bool clicked = hovered && IsMouseClicked(0, id); const bool double_clicked = (hovered && g.IO.MouseClickedCount[0] == 2 && TestKeyOwner(ImGuiKey_MouseLeft, id)); - const bool make_active = (input_requested_by_tabbing || clicked || double_clicked || g.NavActivateId == id); + const bool make_active = (input_requested_by_tabbing || clicked || double_clicked || g.NavActivateId == id || g.NavActivateInputId == id); if (make_active && (clicked || double_clicked)) SetKeyOwner(ImGuiKey_MouseLeft, id); if (make_active && temp_input_allowed) - if (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || double_clicked || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) + if (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavActivateInputId == id) temp_input_is_active = true; // (Optional) simple click (without moving) turns Drag into an InputText if (g.IO.ConfigDragClickToInputText && temp_input_allowed && !temp_input_is_active) if (g.ActiveId == id && hovered && g.IO.MouseReleased[0] && !IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) { - g.NavActivateId = id; + g.NavActivateId = g.NavActivateInputId = id; g.NavActivateFlags = ImGuiActivateFlags_PreferInput; temp_input_is_active = true; } @@ -2469,7 +2395,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); return value_changed; } @@ -2841,7 +2767,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ set_new_value = true; } } - else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) + else if (g.ActiveIdSource == ImGuiInputSource_Nav) { if (g.ActiveIdIsJustActivated) { @@ -3017,18 +2943,18 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + const bool hovered = ItemHoverable(frame_bb, id); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { // Tabbing or CTRL-clicking on Slider turns it into an input box const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; const bool clicked = hovered && IsMouseClicked(0, id); - const bool make_active = (input_requested_by_tabbing || clicked || g.NavActivateId == id); + const bool make_active = (input_requested_by_tabbing || clicked || g.NavActivateId == id || g.NavActivateInputId == id); if (make_active && clicked) SetKeyOwner(ImGuiKey_MouseLeft, id); if (make_active && temp_input_allowed) - if (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) + if (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || g.NavActivateInputId == id) temp_input_is_active = true; if (make_active && !temp_input_is_active) @@ -3072,7 +2998,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); return value_changed; } @@ -3184,9 +3110,9 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + const bool hovered = ItemHoverable(frame_bb, id); const bool clicked = hovered && IsMouseClicked(0, id); - if (clicked || g.NavActivateId == id) + if (clicked || g.NavActivateId == id || g.NavActivateInputId == id) { if (clicked) SetKeyOwner(ImGuiKey_MouseLeft, id); @@ -3287,7 +3213,7 @@ const char* ImParseFormatFindEnd(const char* fmt) } // Extract the format out of a format string with leading or trailing decorations -// fmt = "blah blah" -> return "" +// fmt = "blah blah" -> return fmt // fmt = "%.3f" -> return fmt // fmt = "hello %.3f" -> return fmt + 6 // fmt = "%.3f hello" -> return buf written with "%.3f" @@ -3295,7 +3221,7 @@ const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_ { const char* fmt_start = ImParseFormatFindStart(fmt); if (fmt_start[0] != '%') - return ""; + return fmt; const char* fmt_end = ImParseFormatFindEnd(fmt_start); if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data. return fmt_start; @@ -3320,7 +3246,7 @@ void ImParseFormatSanitizeForPrinting(const char* fmt_in, char* fmt_out, size_t *fmt_out = 0; // Zero-terminate } -// - For scanning we need to remove all width and precision fields and flags "%+3.7f" -> "%f". BUT don't strip types like "%I64d" which includes digits. ! "%07I64d" -> "%I64d" +// - For scanning we need to remove all width and precision fields "%3.7f" -> "%f". BUT don't strip types like "%I64d" which includes digits. ! "%07I64d" -> "%I64d" const char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out, size_t fmt_out_size) { const char* fmt_end = ImParseFormatFindEnd(fmt_in); @@ -3331,7 +3257,7 @@ const char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out, while (fmt_in < fmt_end) { char c = *fmt_in++; - if (!has_type && ((c >= '0' && c <= '9') || c == '.' || c == '+' || c == '#')) + if (!has_type && ((c >= '0' && c <= '9') || c == '.')) continue; has_type |= ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); // Stop skipping digits if (c != '\'' && c != '$' && c != '_') // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '. @@ -3413,14 +3339,9 @@ static inline ImGuiInputTextFlags InputScalar_DefaultCharsFilter(ImGuiDataType d // However this may not be ideal for all uses, as some user code may break on out of bound values. bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max) { - // FIXME: May need to clarify display behavior if format doesn't contain %. - // "%d" -> "%d" / "There are %d items" -> "%d" / "items" -> "%d" (fallback). Also see #6405 - const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); char fmt_buf[32]; char data_buf[32]; format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); - if (format[0] == 0) - format = type_info->PrintFmt; DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format); ImStrTrimBlanks(data_buf); @@ -3431,7 +3352,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags)) { // Backup old value - size_t data_type_size = type_info->Size; + size_t data_type_size = DataTypeGetInfo(data_type)->Size; ImGuiDataTypeTempStorage data_backup; memcpy(&data_backup, p_data, data_type_size); @@ -3475,12 +3396,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data flags |= ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string. bool value_changed = false; - if (p_step == NULL) - { - if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) - value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); - } - else + if (p_step != NULL) { const float button_size = GetFrameHeight(); @@ -3489,7 +3405,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); - IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable); + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags); // Step buttons const ImVec2 backup_frame_padding = style.FramePadding; @@ -3523,6 +3439,11 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data PopID(); EndGroup(); } + else + { + if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) + value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); + } if (value_changed) MarkItemEdited(g.LastItemData.ID); @@ -3657,9 +3578,9 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** return line_count; } -static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) +static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) { - ImGuiContext& g = *ctx; + ImGuiContext& g = *GImGui; ImFont* font = g.Font; const float line_height = g.FontSize; const float scale = line_height / font->FontSize; @@ -3708,14 +3629,14 @@ namespace ImStb static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->CurLenW; } static ImWchar STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { return obj->TextW[idx]; } -static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *GImGui; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); } static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x200000 ? 0 : key; } static ImWchar STB_TEXTEDIT_NEWLINE = '\n'; static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) { const ImWchar* text = obj->TextW.Data; const ImWchar* text_remaining = NULL; - const ImVec2 size = InputTextCalcTextSizeW(obj->Ctx, text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); + const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); r->x0 = 0.0f; r->x1 = size.x; r->baseline_y_delta = size.y; @@ -3724,38 +3645,14 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* ob r->num_chars = (int)(text_remaining - (text + line_start_idx)); } -static bool is_separator(unsigned int c) -{ - return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r' || c=='.' || c=='!'; -} - -static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) -{ - // When ImGuiInputTextFlags_Password is set, we don't want actions such as CTRL+Arrow to leak the fact that underlying data are blanks or separators. - if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) - return 0; - - bool prev_white = ImCharIsBlankW(obj->TextW[idx - 1]); - bool prev_separ = is_separator(obj->TextW[idx - 1]); - bool curr_white = ImCharIsBlankW(obj->TextW[idx]); - bool curr_separ = is_separator(obj->TextW[idx]); - return ((prev_white || prev_separ) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); -} -static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) -{ - if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) - return 0; - - bool prev_white = ImCharIsBlankW(obj->TextW[idx]); - bool prev_separ = is_separator(obj->TextW[idx]); - bool curr_white = ImCharIsBlankW(obj->TextW[idx - 1]); - bool curr_separ = is_separator(obj->TextW[idx - 1]); - return ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); -} +// When ImGuiInputTextFlags_Password is set, we don't want actions such as CTRL+Arrow to leak the fact that underlying data are blanks or separators. +static bool is_separator(unsigned int c) { return ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r'; } +static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (is_separator(obj->TextW[idx - 1]) && !is_separator(obj->TextW[idx]) ) : 1; } +static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (!is_separator(obj->TextW[idx - 1]) && is_separator(obj->TextW[idx])) : 1; } static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } -static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { ImGuiContext& g = *obj->Ctx; if (g.IO.ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); } +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { if (ImGui::GetIO().ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); } #define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h #define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL @@ -3827,7 +3724,6 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const Im #define STB_TEXTEDIT_K_SHIFT 0x400000 #define STB_TEXTEDIT_IMPLEMENTATION -#define STB_TEXTEDIT_memmove memmove #include "imstb_textedit.h" // stb_textedit internally allows for a single undo record to do addition and deletion, but somehow, calling @@ -3885,10 +3781,6 @@ void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count) void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end) { - // Accept null ranges - if (new_text == new_text_end) - return; - const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0; const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text); if (new_text_len + BufTextLen >= BufSize) @@ -3897,7 +3789,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons return; // Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the mildly similar code (until we remove the U16 buffer altogether!) - ImGuiContext& g = *Ctx; + ImGuiContext& g = *GImGui; ImGuiInputTextState* edit_state = &g.InputTextState; IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); IM_ASSERT(Buf == edit_state->TextA.Data); @@ -4001,9 +3893,8 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f // Custom callback filter if (flags & ImGuiInputTextFlags_CallbackCharFilter) { - ImGuiContext& g = *GImGui; ImGuiInputTextCallbackData callback_data; - callback_data.Ctx = &g; + memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; callback_data.EventChar = (ImWchar)c; callback_data.Flags = flags; @@ -4053,29 +3944,6 @@ static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* st p[i] = ImStb::STB_TEXTEDIT_GETCHAR(state, first_diff + i); } -// As InputText() retain textual data and we currently provide a path for user to not retain it (via local variables) -// we need some form of hook to reapply data back to user buffer on deactivation frame. (#4714) -// It would be more desirable that we discourage users from taking advantage of the "user not retaining data" trick, -// but that more likely be attractive when we do have _NoLiveEdit flag available. -void ImGui::InputTextDeactivateHook(ImGuiID id) -{ - ImGuiContext& g = *GImGui; - ImGuiInputTextState* state = &g.InputTextState; - if (id == 0 || state->ID != id) - return; - g.InputTextDeactivatedState.ID = state->ID; - if (state->Flags & ImGuiInputTextFlags_ReadOnly) - { - g.InputTextDeactivatedState.TextA.resize(0); // In theory this data won't be used, but clear to be neat. - } - else - { - IM_ASSERT(state->TextA.Data != 0); - g.InputTextDeactivatedState.TextA.resize(state->CurLenA + 1); - memcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data, state->CurLenA + 1); - } -} - // Edit a string of text // - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!". // This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match @@ -4163,7 +4031,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ return false; item_status_flags = g.LastItemData.StatusFlags; } - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + const bool hovered = ItemHoverable(frame_bb, id); if (hovered) g.MouseCursor = ImGuiMouseCursor_TextInput; @@ -4171,7 +4039,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImGuiInputTextState* state = GetInputTextState(id); const bool input_requested_by_tabbing = (item_status_flags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; - const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard))); + const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_Keyboard)); const bool user_clicked = hovered && io.MouseClicked[0]; const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); @@ -4181,7 +4049,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX; - const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline); // state != NULL means its our state. + const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline); const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav || input_requested_by_tabbing); const bool init_state = (init_make_active || user_scroll_active); if ((init_state && g.ActiveId != id) || init_changed_specs) @@ -4190,9 +4058,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state = &g.InputTextState; state->CursorAnimReset(); - // Backup state of deactivating item so they'll have a chance to do a write to output buffer on the same frame they report IsItemDeactivatedAfterEdit (#4714) - InputTextDeactivateHook(state->ID); - // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar) // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode) const int buf_len = (int)strlen(buf); @@ -4240,7 +4105,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863) } - const bool is_osx = io.ConfigMacOSXBehaviors; if (g.ActiveId != id && init_make_active) { IM_ASSERT(state && state->ID == id); @@ -4263,10 +4127,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ SetKeyOwner(ImGuiKey_PageUp, id); SetKeyOwner(ImGuiKey_PageDown, id); } - if (is_osx) - SetKeyOwner(ImGuiMod_Alt, id); if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character. - SetShortcutRouting(ImGuiKey_Tab, id); + SetKeyOwner(ImGuiKey_Tab, id); } // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) @@ -4328,11 +4190,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. // Down the line we should have a cleaner library-wide concept of Selected vs Active. g.ActiveIdAllowOverlap = !io.MouseDown[0]; + g.WantTextInputNextFrame = 1; // Edit in progress const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX; const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f)); + const bool is_osx = io.ConfigMacOSXBehaviors; if (select_all) { state->SelectAll(); @@ -4395,7 +4259,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // We expect backends to emit a Tab key but some also emit a Tab character which we ignore (#2467, #1336) // (For Tab and Enter: Win32/SFML/Allegro are sending both keys and chars, GLFW and SDL are only sending keys. For Space they all send all threes) - if ((flags & ImGuiInputTextFlags_AllowTabInput) && Shortcut(ImGuiKey_Tab, id) && !is_readonly) + const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); + if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressed(ImGuiKey_Tab) && !ignore_char_inputs && !io.KeyShift && !is_readonly) { unsigned int c = '\t'; // Insert TAB if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) @@ -4404,7 +4269,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Process regular text input (before we check for Return because using some IME will effectively send a Return?) // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. - const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); if (io.InputQueueCharacters.Size > 0) { if (!ignore_char_inputs && !is_readonly && !input_requested_by_nav) @@ -4433,6 +4297,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->Stb.row_count_per_page = row_count_per_page; const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); + const bool is_osx = io.ConfigMacOSXBehaviors; const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End @@ -4461,16 +4326,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; } else if (IsKeyPressed(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } else if (IsKeyPressed(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } - else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut) - { - if (!state->HasSelection()) - { - // OSX doesn't seem to have Super+Delete to delete until end-of-line, so we don't emulate that (as opposed to Super+Backspace) - if (is_wordmove_key_down) - state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); - } - state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); - } + else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } else if (IsKeyPressed(ImGuiKey_Backspace) && !is_readonly) { if (!state->HasSelection()) @@ -4505,7 +4361,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { if (flags & ImGuiInputTextFlags_EscapeClearsAll) { - if (buf[0] != 0) + if (state->CurLenA > 0) { revert_edit = true; } @@ -4560,10 +4416,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const int clipboard_len = (int)strlen(clipboard); ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len + 1) * sizeof(ImWchar)); int clipboard_filtered_len = 0; - for (const char* s = clipboard; *s != 0; ) + for (const char* s = clipboard; *s; ) { unsigned int c; s += ImTextCharFromUtf8(&c, s, NULL); + if (c == 0) + break; if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard)) continue; clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; @@ -4593,10 +4451,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (flags & ImGuiInputTextFlags_EscapeClearsAll) { // Clear input - IM_ASSERT(buf[0] != 0); apply_new_text = ""; apply_new_text_length = 0; - value_changed = true; STB_TEXTEDIT_CHARTYPE empty_string; stb_textedit_replace(state, &state->Stb, &empty_string, 0); } @@ -4606,7 +4462,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Push records into the undo stack so we can CTRL+Z the revert operation itself apply_new_text = state->InitialTextA.Data; apply_new_text_length = state->InitialTextA.Size - 1; - value_changed = true; ImVector w_text; if (apply_new_text_length > 0) { @@ -4625,12 +4480,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL); } - // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer - // before clearing ActiveId, even though strictly speaking it wasn't modified on this frame. + // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer before clearing ActiveId, even though strictly speaking it wasn't modified on this frame. // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. - // This also allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage - // (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object - // unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize). + // This also allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize). const bool apply_edit_back_to_user_buffer = !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); if (apply_edit_back_to_user_buffer) { @@ -4647,7 +4499,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. ImGuiInputTextFlags event_flag = 0; ImGuiKey event_key = ImGuiKey_None; - if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && Shortcut(ImGuiKey_Tab, id)) + if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressed(ImGuiKey_Tab)) { event_flag = ImGuiInputTextFlags_CallbackCompletion; event_key = ImGuiKey_Tab; @@ -4674,7 +4526,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (event_flag) { ImGuiInputTextCallbackData callback_data; - callback_data.Ctx = &g; + memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); callback_data.EventFlag = event_flag; callback_data.Flags = flags; callback_data.UserData = callback_user_data; @@ -4723,24 +4575,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { apply_new_text = state->TextA.Data; apply_new_text_length = state->CurLenA; - value_changed = true; } } } - // Handle reapplying final data on deactivation (see InputTextDeactivateHook() for details) - if (g.InputTextDeactivatedState.ID == id) - { - if (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly && strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0) - { - apply_new_text = g.InputTextDeactivatedState.TextA.Data; - apply_new_text_length = g.InputTextDeactivatedState.TextA.Size - 1; - value_changed = true; - //IMGUI_DEBUG_LOG("InputText(): apply Deactivated data for 0x%08X: \"%.*s\".\n", id, apply_new_text_length, apply_new_text); - } - g.InputTextDeactivatedState.ID = 0; - } - // Copy result to user buffer. This can currently only happen when (g.ActiveId == id) if (apply_new_text != NULL) { @@ -4751,7 +4589,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_resizable) { ImGuiInputTextCallbackData callback_data; - callback_data.Ctx = &g; callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; callback_data.Flags = flags; callback_data.Buf = buf; @@ -4768,14 +4605,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); + value_changed = true; } // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) - // Otherwise request text input ahead for next frame. - if (g.ActiveId == id && clear_active_id) + if (clear_active_id && g.ActiveId == id) ClearActiveID(); - else if (g.ActiveId == id) - g.WantTextInputNextFrame = 1; // Render frame if (!is_multiline) @@ -4855,11 +4690,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ searches_result_line_no[1] = line_count; // Calculate 2d position by finding the beginning of the line and measuring distance - cursor_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; + cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; cursor_offset.y = searches_result_line_no[0] * g.FontSize; if (searches_result_line_no[1] >= 0) { - select_start_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; + select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; select_start_offset.y = searches_result_line_no[1] * g.FontSize; } @@ -4928,7 +4763,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } else { - ImVec2 rect_size = InputTextCalcTextSizeW(&g, p, text_selected_end, &p, NULL, true); + ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true); if (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn)); rect.ClipWith(clip_rect); @@ -4990,9 +4825,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)... Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); - g.NextItemData.ItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; + ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; EndChild(); item_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow); + g.CurrentItemFlags = backup_item_flags; // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active... // FIXME: This quite messy/tricky, should attempt to get rid of the child window. @@ -5018,7 +4855,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited)) MarkItemEdited(id); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) return validated; else @@ -5033,8 +4870,7 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) ImStb::StbUndoState* undo_state = &stb_state->undostate; Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId); DebugLocateItemOnHover(state->ID); - Text("CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenW, state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end); - Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); + Text("CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenA, state->CurLenW, stb_state->cursor, stb_state->select_start, stb_state->select_end); Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 15), true)) // Visualize undo state { @@ -5081,32 +4917,28 @@ bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flag return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha); } -static void ColorEditRestoreH(const float* col, float* H) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(g.ColorEditCurrentID != 0); - if (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) - return; - *H = g.ColorEditSavedHue; -} - // ColorEdit supports RGB and HSV inputs. In case of RGB input resulting color may have undefined hue and/or saturation. // Since widget displays both RGB and HSV values we must preserve hue and saturation to prevent these values resetting. static void ColorEditRestoreHS(const float* col, float* H, float* S, float* V) { + // This check is optional. Suppose we have two color widgets side by side, both widgets display different colors, but both colors have hue and/or saturation undefined. + // With color check: hue/saturation is preserved in one widget. Editing color in one widget would reset hue/saturation in another one. + // Without color check: common hue/saturation would be displayed in all widgets that have hue/saturation undefined. + // g.ColorEditLastColor is stored as ImU32 RGB value: this essentially gives us color equality check with reduced precision. + // Tiny external color changes would not be detected and this check would still pass. This is OK, since we only restore hue/saturation _only_ if they are undefined, + // therefore this change flipping hue/saturation from undefined to a very tiny value would still be represented in color picker. ImGuiContext& g = *GImGui; - IM_ASSERT(g.ColorEditCurrentID != 0); - if (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) + if (g.ColorEditLastColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) return; // When S == 0, H is undefined. // When H == 1 it wraps around to 0. - if (*S == 0.0f || (*H == 0.0f && g.ColorEditSavedHue == 1)) - *H = g.ColorEditSavedHue; + if (*S == 0.0f || (*H == 0.0f && g.ColorEditLastHue == 1)) + *H = g.ColorEditLastHue; // When V == 0, S is undefined. if (*V == 0.0f) - *S = g.ColorEditSavedSat; + *S = g.ColorEditLastSat; } // Edit colors components (each component in 0.0f..1.0f range). @@ -5129,9 +4961,6 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag BeginGroup(); PushID(label); - const bool set_current_color_edit_id = (g.ColorEditCurrentID == 0); - if (set_current_color_edit_id) - g.ColorEditCurrentID = window->IDStack.back(); // If we're not showing any slider there's no point in doing any HSV conversions const ImGuiColorEditFlags flags_untouched = flags; @@ -5165,7 +4994,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); else if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV)) { - // Hue is lost when converting from grayscale rgb (saturation=0). Restore it. + // Hue is lost when converting from greyscale rgb (saturation=0). Restore it. ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); ColorEditRestoreHS(col, &f[0], &f[1], &f[2]); } @@ -5304,11 +5133,10 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag f[n] = i[n] / 255.0f; if ((flags & ImGuiColorEditFlags_DisplayHSV) && (flags & ImGuiColorEditFlags_InputRGB)) { - g.ColorEditSavedHue = f[0]; - g.ColorEditSavedSat = f[1]; + g.ColorEditLastHue = f[0]; + g.ColorEditLastSat = f[1]; ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); - g.ColorEditSavedID = g.ColorEditCurrentID; - g.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(f[0], f[1], f[2], 0)); + g.ColorEditLastColor = ColorConvertFloat4ToU32(ImVec4(f[0], f[1], f[2], 0)); } if ((flags & ImGuiColorEditFlags_DisplayRGB) && (flags & ImGuiColorEditFlags_InputHSV)) ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); @@ -5320,8 +5148,6 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag col[3] = f[3]; } - if (set_current_color_edit_id) - g.ColorEditCurrentID = 0; PopID(); EndGroup(); @@ -5395,9 +5221,6 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl g.NextItemData.ClearFlags(); PushID(label); - const bool set_current_color_edit_id = (g.ColorEditCurrentID == 0); - if (set_current_color_edit_id) - g.ColorEditCurrentID = window->IDStack.back(); BeginGroup(); if (!(flags & ImGuiColorEditFlags_NoSidePreview)) @@ -5446,7 +5269,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl float R = col[0], G = col[1], B = col[2]; if (flags & ImGuiColorEditFlags_InputRGB) { - // Hue is lost when converting from grayscale rgb (saturation=0). Restore it. + // Hue is lost when converting from greyscale rgb (saturation=0). Restore it. ColorConvertRGBtoHSV(R, G, B, H, S, V); ColorEditRestoreHS(col, &H, &S, &V); } @@ -5501,7 +5324,10 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl { S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1)); V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); - ColorEditRestoreH(col, &H); // Greatly reduces hue jitter and reset to 0 when hue == 255 and color is rapidly modified using SV square. + + // Greatly reduces hue jitter and reset to 0 when hue == 255 and color is rapidly modified using SV square. + if (g.ColorEditLastColor == ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) + H = g.ColorEditLastHue; value_changed = value_changed_sv = true; } if (!(flags & ImGuiColorEditFlags_NoOptions)) @@ -5576,10 +5402,9 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if (flags & ImGuiColorEditFlags_InputRGB) { ColorConvertHSVtoRGB(H, S, V, col[0], col[1], col[2]); - g.ColorEditSavedHue = H; - g.ColorEditSavedSat = S; - g.ColorEditSavedID = g.ColorEditCurrentID; - g.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)); + g.ColorEditLastHue = H; + g.ColorEditLastSat = S; + g.ColorEditLastColor = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)); } else if (flags & ImGuiColorEditFlags_InputHSV) { @@ -5681,7 +5506,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl float sin_hue_angle = ImSin(H * 2.0f * IM_PI); ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f); float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f; - int hue_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(hue_cursor_rad); // Lock segment count so the +1 one matches others. + int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32); draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments); draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, col_midgrey, hue_cursor_segments); draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments); @@ -5691,10 +5516,13 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle); ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle); ImVec2 uv_white = GetFontTexUvWhitePixel(); - draw_list->PrimReserve(3, 3); + draw_list->PrimReserve(6, 6); draw_list->PrimVtx(tra, uv_white, hue_color32); - draw_list->PrimVtx(trb, uv_white, col_black); + draw_list->PrimVtx(trb, uv_white, hue_color32); draw_list->PrimVtx(trc, uv_white, col_white); + draw_list->PrimVtx(tra, uv_white, 0); + draw_list->PrimVtx(trb, uv_white, col_black); + draw_list->PrimVtx(trc, uv_white, 0); draw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f); sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V)); } @@ -5717,10 +5545,9 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range) float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f; - int sv_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(sv_cursor_rad); // Lock segment count so the +1 one matches others. - draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, sv_cursor_segments); - draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, sv_cursor_segments); - draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, sv_cursor_segments); + draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, 12); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, 12); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, 12); // Render alpha bar if (alpha_bar) @@ -5741,8 +5568,6 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId MarkItemEdited(g.LastItemData.ID); - if (set_current_color_edit_id) - g.ColorEditCurrentID = 0; PopID(); return value_changed; @@ -5826,7 +5651,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl } // Tooltip - if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered && IsItemHovered(ImGuiHoveredFlags_ForTooltip)) + if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); return pressed; @@ -5856,8 +5681,7 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags { ImGuiContext& g = *GImGui; - if (!BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None)) - return; + BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None); const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text; if (text_end > text) { @@ -6191,8 +6015,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l } ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None; - if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap)) - button_flags |= ImGuiButtonFlags_AllowOverlap; + if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) + button_flags |= ImGuiButtonFlags_AllowItemOverlap; if (!is_leaf) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; @@ -6248,13 +6072,11 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open) { toggled = true; - NavClearPreferredPosForAxis(ImGuiAxis_X); NavMoveRequestCancel(); } if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority? { toggled = true; - NavClearPreferredPosForAxis(ImGuiAxis_X); NavMoveRequestCancel(); } @@ -6265,6 +6087,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen; } } + if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) + SetItemAllowOverlap(); // In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger. if (selected != was_selected) //-V547 @@ -6282,9 +6106,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (flags & ImGuiTreeNodeFlags_Bullet) RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); else if (!is_leaf) - RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f); + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f); else // Leaf without bullet, left-adjusted text - text_pos.x -= text_offset_x -padding.x; + text_pos.x -= text_offset_x; if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) frame_bb.Max.x -= g.FontSize + style.FramePadding.x; @@ -6304,7 +6128,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (flags & ImGuiTreeNodeFlags_Bullet) RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); else if (!is_leaf) - RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f); + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f); if (g.LogEnabled) LogSetNextTextDecoration(">", NULL); RenderText(text_pos, label, label_end, false); @@ -6408,7 +6232,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl ImGuiID id = window->GetID(label); flags |= ImGuiTreeNodeFlags_CollapsingHeader; if (p_visible) - flags |= ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; + flags |= ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; bool is_open = TreeNodeBehavior(id, flags, label); if (p_visible != NULL) { @@ -6437,7 +6261,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl // Tip: pass a non-visible label (e.g. "##hello") then you can use the space to draw other text or image. // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id. -// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowOverlap are also frequently used flags. +// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowItemOverlap are also frequently used flags. // FIXME: Selectable() with (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported. bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) { @@ -6521,7 +6345,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } - if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; } + if (flags & ImGuiSelectableFlags_AllowItemOverlap) { button_flags |= ImGuiButtonFlags_AllowItemOverlap; } const bool was_selected = selected; bool hovered, held; @@ -6550,11 +6374,16 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (pressed) MarkItemEdited(id); + if (flags & ImGuiSelectableFlags_AllowItemOverlap) + SetItemAllowOverlap(); + // In this branch, Selectable() cannot toggle the selection so this will never trigger. if (selected != was_selected) //-V547 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection; // Render + if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld)) + hovered = true; if (hovered || selected) { const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); @@ -6639,6 +6468,20 @@ bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) return true; } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// OBSOLETED in 1.81 (from February 2021) +bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) +{ + // If height_in_items == -1, default height is maximum 7. + ImGuiContext& g = *GImGui; + float height_in_items_f = (height_in_items < 0 ? ImMin(items_count, 7) : height_in_items) + 0.25f; + ImVec2 size; + size.x = 0.0f; + size.y = GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f; + return BeginListBox(label, size); +} +#endif + void ImGui::EndListBox() { ImGuiContext& g = *GImGui; @@ -6715,7 +6558,7 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v // - others https://github.com/ocornut/imgui/wiki/Useful-Extensions //------------------------------------------------------------------------- -int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg) +int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -6726,7 +6569,10 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0f); + if (frame_size.x == 0.0f) + frame_size.x = CalcItemWidth(); + if (frame_size.y == 0.0f) + frame_size.y = label_size.y + (style.FramePadding.y * 2); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); @@ -6734,7 +6580,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, 0, &frame_bb)) return -1; - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + const bool hovered = ItemHoverable(frame_bb, id); // Determine scale from values if not specified if (scale_min == FLT_MAX || scale_max == FLT_MAX) @@ -7102,7 +6948,7 @@ void ImGui::EndMainMenuBar() // FIXME: With this strategy we won't be able to restore a NULL focus. ImGuiContext& g = *GImGui; if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest) - FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild); + FocusTopMostWindowUnderOne(g.NavWindow, NULL); End(); } @@ -7116,9 +6962,9 @@ static bool IsRootOfOpenMenuSet() // Initially we used 'upper_popup->OpenParentId == window->IDStack.back()' to differentiate multiple menu sets from each others // (e.g. inside menu bar vs loose menu items) based on parent ID. - // This would however prevent the use of e.g. PushID() user code submitting menus. + // This would however prevent the use of e.g. PuhsID() user code submitting menus. // Previously this worked between popup and a first child menu because the first child menu always had the _ChildWindow flag, - // making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects. + // making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects. // Instead we don't treat Popup specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup // doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between root window/popup and first child menu. // In the end, lack of ID check made it so we could no longer differentiate between separate menu sets. To compensate for that, we at least check parent window nav layer. @@ -7126,9 +6972,7 @@ static bool IsRootOfOpenMenuSet() // open on hover, but that should be a lesser problem, because if such menus are close in proximity in window content then it won't feel weird and if they are far apart // it likely won't be a problem anyone runs into. const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size]; - if (window->DC.NavLayerCurrent != upper_popup->ParentNavLayer) - return false; - return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true); + return (window->DC.NavLayerCurrent == upper_popup->ParentNavLayer && upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu)); } bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) @@ -7193,7 +7037,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); float w = label_size.x; ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); - pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y)); + pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, 0.0f)); RenderText(text_pos, label); PopStyleVar(); window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). @@ -7209,7 +7053,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); - pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); + pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); RenderText(text_pos, label); if (icon_w > 0.0f) RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); @@ -7401,7 +7245,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); - pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); + pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) { RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label); @@ -7453,17 +7297,11 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, // - TabBarCalcTabID() [Internal] // - TabBarCalcMaxTabWidth() [Internal] // - TabBarFindTabById() [Internal] -// - TabBarFindTabByOrder() [Internal] -// - TabBarGetCurrentTab() [Internal] -// - TabBarGetTabName() [Internal] // - TabBarRemoveTab() [Internal] // - TabBarCloseTab() [Internal] // - TabBarScrollClamp() [Internal] // - TabBarScrollToTab() [Internal] -// - TabBarQueueFocus() [Internal] -// - TabBarQueueReorder() [Internal] -// - TabBarProcessReorderFromMousePos() [Internal] -// - TabBarProcessReorder() [Internal] +// - TabBarQueueChangeTabOrder() [Internal] // - TabBarScrollingButtons() [Internal] // - TabBarTabListPopupButton() [Internal] //------------------------------------------------------------------------- @@ -7480,7 +7318,7 @@ struct ImGuiTabBarSection namespace ImGui { static void TabBarLayout(ImGuiTabBar* tab_bar); - static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window); + static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label); static float TabBarCalcMaxTabWidth(); static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling); static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections); @@ -7588,7 +7426,6 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG tab_bar->ItemSpacingY = g.Style.ItemSpacing.y; tab_bar->FramePadding = g.Style.FramePadding; tab_bar->TabsActiveCount = 0; - tab_bar->LastTabItemIdx = -1; tab_bar->BeginCount = 1; // Set cursor pos in a way which only be used in the off-chance the user erroneously submits item before BeginTabItem(): items will overlap @@ -7637,7 +7474,6 @@ void ImGui::EndTabBar() if (tab_bar->BeginCount > 1) window->DC.CursorPos = tab_bar->BackupCursorPos; - tab_bar->LastTabItemIdx = -1; if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) PopID(); @@ -7645,12 +7481,6 @@ void ImGui::EndTabBar() g.CurrentTabBar = g.CurrentTabBarStack.empty() ? NULL : GetTabBarFromTabBarRef(g.CurrentTabBarStack.back()); } -// Scrolling happens only in the central section (leading/trailing sections are not scrolling) -static float TabBarCalcScrollableWidth(ImGuiTabBar* tab_bar, ImGuiTabBarSection* sections) -{ - return tab_bar->BarRect.GetWidth() - sections[0].Width - sections[2].Width - sections[1].Spacing; -} - // This is called only once a frame before by the first call to ItemTab() // The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() functions. static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) @@ -7753,7 +7583,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) // Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar. // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. - const char* tab_name = TabBarGetTabName(tab_bar, tab); + const char* tab_name = tab_bar->GetTabName(tab); const bool has_close_button_or_unsaved_marker = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument); tab->ContentWidth = (tab->RequestedWidth >= 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x; @@ -7832,7 +7662,6 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) { ImGuiTabItem* tab = &tab_bar->Tabs[section_tab_index + tab_n]; tab->Offset = tab_offset; - tab->NameOffset = -1; tab_offset += tab->Width + (tab_n < section->TabCount - 1 ? g.Style.ItemInnerSpacing.x : 0.0f); } tab_bar->WidthAllTabs += ImMax(section->Width + section->Spacing, 0.0f); @@ -7840,9 +7669,6 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) section_tab_index += section->TabCount; } - // Clear name buffers - tab_bar->TabsNames.Buf.resize(0); - // If we have lost the selected tab, select the next most recently active one if (found_selected_tab_id == false) tab_bar->SelectedTabId = 0; @@ -7853,23 +7679,9 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) tab_bar->VisibleTabId = tab_bar->SelectedTabId; tab_bar->VisibleTabWasSubmitted = false; - // Apply request requests + // Update scrolling if (scroll_to_tab_id != 0) TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections); - else if ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) && IsMouseHoveringRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, true) && IsWindowContentHoverable(g.CurrentWindow)) - { - const float wheel = g.IO.MouseWheelRequestAxisSwap ? g.IO.MouseWheel : g.IO.MouseWheelH; - const ImGuiKey wheel_key = g.IO.MouseWheelRequestAxisSwap ? ImGuiKey_MouseWheelY : ImGuiKey_MouseWheelX; - if (TestKeyOwner(wheel_key, tab_bar->ID) && wheel != 0.0f) - { - const float scroll_step = wheel * TabBarCalcScrollableWidth(tab_bar, sections) / 3.0f; - tab_bar->ScrollingTargetDistToVisibility = 0.0f; - tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget - scroll_step); - } - SetKeyOwner(wheel_key, tab_bar->ID); - } - - // Update scrolling tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim); tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget); if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget) @@ -7888,6 +7700,10 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) tab_bar->ScrollingRectMinX = tab_bar->BarRect.Min.x + sections[0].Width + sections[0].Spacing; tab_bar->ScrollingRectMaxX = tab_bar->BarRect.Max.x - sections[2].Width - sections[1].Spacing; + // Clear name buffers + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + tab_bar->TabsNames.Buf.resize(0); + // Actual layout in host window (we don't do it in BeginTabBar() so as not to waste an extra frame) ImGuiWindow* window = g.CurrentWindow; window->DC.CursorPos = tab_bar->BarRect.Min; @@ -7895,11 +7711,9 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, tab_bar->BarRect.Min.x + tab_bar->WidthAllTabsIdeal); } -// Dockable windows uses Name/ID in the global namespace. Non-dockable items use the ID stack. -static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window) +// Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack. +static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label) { - IM_ASSERT(docked_window == NULL); // master branch only - IM_UNUSED(docked_window); if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) { ImGuiID id = ImHashStr(label); @@ -7928,30 +7742,7 @@ ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id) return NULL; } -// Order = visible order, not submission order! (which is tab->BeginOrder) -ImGuiTabItem* ImGui::TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order) -{ - if (order < 0 || order >= tab_bar->Tabs.Size) - return NULL; - return &tab_bar->Tabs[order]; -} - -ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar) -{ - if (tab_bar->LastTabItemIdx <= 0 || tab_bar->LastTabItemIdx >= tab_bar->Tabs.Size) - return NULL; - return &tab_bar->Tabs[tab_bar->LastTabItemIdx]; -} - -const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) -{ - if (tab->NameOffset == -1) - return "N/A"; - IM_ASSERT(tab->NameOffset < tab_bar->TabsNames.Buf.Size); - return tab_bar->TabsNames.Buf.Data + tab->NameOffset; -} - -// The *TabId fields are already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. +// The *TabId fields be already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) { if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) @@ -7982,7 +7773,7 @@ void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { // Actually select before expecting closure attempt (on an UnsavedDocument tab user is expect to e.g. show a popup) if (tab_bar->VisibleTabId != tab->ID) - TabBarQueueFocus(tab_bar, tab); + tab_bar->NextSelectedTabId = tab->ID; } } @@ -8003,10 +7794,11 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui ImGuiContext& g = *GImGui; float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) - int order = TabBarGetTabOrder(tab_bar, tab); + int order = tab_bar->GetTabOrder(tab); // Scrolling happens only in the central section (leading/trailing sections are not scrolling) - float scrollable_width = TabBarCalcScrollableWidth(tab_bar, sections); + // FIXME: This is all confusing. + float scrollable_width = tab_bar->BarRect.GetWidth() - sections[0].Width - sections[2].Width - sections[1].Spacing; // We make all tabs positions all relative Sections[0].Width to make code simpler float tab_x1 = tab->Offset - sections[0].Width + (order > sections[0].TabCount - 1 ? -margin : 0.0f); @@ -8026,12 +7818,7 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui } } -void ImGui::TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) -{ - tab_bar->NextSelectedTabId = tab->ID; -} - -void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset) +void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset) { IM_ASSERT(offset != 0); IM_ASSERT(tab_bar->ReorderRequestTabId == 0); @@ -8039,7 +7826,7 @@ void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offs tab_bar->ReorderRequestOffset = (ImS16)offset; } -void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* src_tab, ImVec2 mouse_pos) +void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* src_tab, ImVec2 mouse_pos) { ImGuiContext& g = *GImGui; IM_ASSERT(tab_bar->ReorderRequestTabId == 0); @@ -8082,7 +7869,7 @@ bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar) return false; //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools - int tab2_order = TabBarGetTabOrder(tab_bar, tab1) + tab_bar->ReorderRequestOffset; + int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestOffset; if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size) return false; @@ -8142,7 +7929,7 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) if (select_dir != 0) if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) { - int selected_order = TabBarGetTabOrder(tab_bar, tab_item); + int selected_order = tab_bar->GetTabOrder(tab_item); int target_order = selected_order + select_dir; // Skip tab item buttons until another tab item is found or end is reached @@ -8194,7 +7981,7 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) if (tab->Flags & ImGuiTabItemFlags_Button) continue; - const char* tab_name = TabBarGetTabName(tab_bar, tab); + const char* tab_name = tab_bar->GetTabName(tab); if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID)) tab_to_select = tab; } @@ -8233,7 +8020,7 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f } IM_ASSERT(!(flags & ImGuiTabItemFlags_Button)); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! - bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL); + bool ret = TabItemEx(tab_bar, label, p_open, flags); if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; @@ -8274,10 +8061,10 @@ bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags) IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); return false; } - return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL); + return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder); } -bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window) +bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags) { // Layout whole tab bar if not already done ImGuiContext& g = *GImGui; @@ -8292,7 +8079,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, return false; const ImGuiStyle& style = g.Style; - const ImGuiID id = TabBarCalcTabID(tab_bar, label, docked_window); + const ImGuiID id = TabBarCalcTabID(tab_bar, label); // If the user called us with *p_open == false, we early out and don't render. // We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID. @@ -8342,25 +8129,18 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, tab->LastFrameVisible = g.FrameCount; tab->Flags = flags; - // Append name _WITH_ the zero-terminator - if (docked_window != NULL) - { - IM_ASSERT(docked_window == NULL); // master branch only - } - else - { - tab->NameOffset = (ImS32)tab_bar->TabsNames.size(); - tab_bar->TabsNames.append(label, label + strlen(label) + 1); - } + // Append name with zero-terminator + tab->NameOffset = (ImS32)tab_bar->TabsNames.size(); + tab_bar->TabsNames.append(label, label + strlen(label) + 1); // Update selected tab if (!is_tab_button) { if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0) if (!tab_bar_appearing || tab_bar->SelectedTabId == 0) - TabBarQueueFocus(tab_bar, tab); // New tabs gets activated + tab_bar->NextSelectedTabId = id; // New tabs gets activated if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // _SetSelected can only be passed on explicit tab bar - TabBarQueueFocus(tab_bar, tab); + tab_bar->NextSelectedTabId = id; } // Lock visibility @@ -8418,14 +8198,17 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } // Click to Select a tab - // Allow the close button to overlap - ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap); + ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowItemOverlap); if (g.DragDropActive) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); if (pressed && !is_tab_button) - TabBarQueueFocus(tab_bar, tab); + tab_bar->NextSelectedTabId = id; + + // Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs to be hovered) + if (g.ActiveId != id) + SetItemAllowOverlap(); // Drag and drop: re-order tabs if (held && !tab_appearing && IsMouseDragging(0)) @@ -8462,8 +8245,9 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); - if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button) - TabBarQueueFocus(tab_bar, tab); + if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1))) + if (!is_tab_button) + tab_bar->NextSelectedTabId = id; if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; @@ -8491,7 +8275,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // FIXME: We may want disabled tab to still display the tooltip? if (text_clipped && g.HoveredId == id && !held) if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip)) - SetItemTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); + if (IsItemHovered(ImGuiHoveredFlags_DelayNormal)) + SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected if (is_tab_button) @@ -8509,7 +8294,7 @@ void ImGui::SetTabItemClosed(const char* label) if (is_within_manual_tab_bar) { ImGuiTabBar* tab_bar = g.CurrentTabBar; - ImGuiID tab_id = TabBarCalcTabID(tab_bar, label, NULL); + ImGuiID tab_id = TabBarCalcTabID(tab_bar, label); if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) tab->WantClose = true; // Will be processed by next call to TabBarLayout() } @@ -8527,12 +8312,6 @@ ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button_or_unsave return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y); } -ImVec2 ImGui::TabItemCalcSize(ImGuiWindow*) -{ - IM_ASSERT(0); // This function exists to facilitate merge with 'docking' branch. - return ImVec2(0.0f, 0.0f); -} - void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) { // While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it. diff --git a/3rdparty/bgfx/3rdparty/dear-imgui/widgets/memory_editor.inl b/3rdparty/bgfx/3rdparty/dear-imgui/widgets/memory_editor.inl index 4ca722f4eed..ce34f5d6427 100644 --- a/3rdparty/bgfx/3rdparty/dear-imgui/widgets/memory_editor.inl +++ b/3rdparty/bgfx/3rdparty/dear-imgui/widgets/memory_editor.inl @@ -207,7 +207,7 @@ namespace ImGui AlignTextToFramePadding(); PushItemWidth(50); - PushTabStop(false); + PushAllowKeyboardFocus(false); int rows_backup = Rows; if (DragInt("##rows", &Rows, 0.2f, 4, 32, "%.0f rows")) { @@ -216,7 +216,7 @@ namespace ImGui SetWindowSize(new_window_size); } - PopTabStop(); + PopAllowKeyboardFocus(); PopItemWidth(); SameLine(); Text("Range %0*x..%0*x", addr_digits_count, (int)base_display_addr, addr_digits_count, (int)base_display_addr+mem_size-1); diff --git a/3rdparty/bgfx/3rdparty/dear-imgui/widgets/range_slider.inl b/3rdparty/bgfx/3rdparty/dear-imgui/widgets/range_slider.inl index 6d6180b32d8..419ec763872 100644 --- a/3rdparty/bgfx/3rdparty/dear-imgui/widgets/range_slider.inl +++ b/3rdparty/bgfx/3rdparty/dear-imgui/widgets/range_slider.inl @@ -173,7 +173,7 @@ bool RangeSliderFloat(const char* label, float* v1, float* v2, float v_min, floa return false; } - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + const bool hovered = ItemHoverable(frame_bb, id); if (hovered) SetHoveredID(id); diff --git a/3rdparty/bgfx/3rdparty/glslang/OGLCompilersDLL/InitializeDll.cpp b/3rdparty/bgfx/3rdparty/glslang/OGLCompilersDLL/InitializeDll.cpp index ab3762e011f..abea9108b15 100644 --- a/3rdparty/bgfx/3rdparty/glslang/OGLCompilersDLL/InitializeDll.cpp +++ b/3rdparty/bgfx/3rdparty/glslang/OGLCompilersDLL/InitializeDll.cpp @@ -32,6 +32,134 @@ // POSSIBILITY OF SUCH DAMAGE. // +#define SH_EXPORTING + +#include + +#include "InitializeDll.h" +#include "../glslang/Include/InitializeGlobals.h" +#include "../glslang/Public/ShaderLang.h" +#include "../glslang/Include/PoolAlloc.h" + namespace glslang { +OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX; + +// Per-process initialization. +// Needs to be called at least once before parsing, etc. is done. +// Will also do thread initialization for the calling thread; other +// threads will need to do that explicitly. +bool InitProcess() +{ + glslang::GetGlobalLock(); + + if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) { + // + // Function is re-entrant. + // + + glslang::ReleaseGlobalLock(); + return true; + } + + ThreadInitializeIndex = OS_AllocTLSIndex(); + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitProcess(): Failed to allocate TLS area for init flag"); + + glslang::ReleaseGlobalLock(); + return false; + } + + if (! InitializePoolIndex()) { + assert(0 && "InitProcess(): Failed to initialize global pool"); + + glslang::ReleaseGlobalLock(); + return false; + } + + if (! InitThread()) { + assert(0 && "InitProcess(): Failed to initialize thread"); + + glslang::ReleaseGlobalLock(); + return false; + } + + glslang::ReleaseGlobalLock(); + return true; +} + +// Per-thread scoped initialization. +// Must be called at least once by each new thread sharing the +// symbol tables, etc., needed to parse. +bool InitThread() +{ + // + // This function is re-entrant + // + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitThread(): Process hasn't been initalised."); + return false; + } + + if (OS_GetTLSValue(ThreadInitializeIndex) != 0) + return true; + + if (! OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) { + assert(0 && "InitThread(): Unable to set init flag."); + return false; + } + + glslang::SetThreadPoolAllocator(nullptr); + + return true; +} + +// Not necessary to call this: InitThread() is reentrant, and the need +// to do per thread tear down has been removed. +// +// This is kept, with memory management removed, to satisfy any exiting +// calls to it that rely on it. +bool DetachThread() +{ + bool success = true; + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) + return true; + + // + // Function is re-entrant and this thread may not have been initialized. + // + if (OS_GetTLSValue(ThreadInitializeIndex) != 0) { + if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)0)) { + assert(0 && "DetachThread(): Unable to clear init flag."); + success = false; + } + } + + return success; +} + +// Not necessary to call this: InitProcess() is reentrant. +// +// This is kept, with memory management removed, to satisfy any exiting +// calls to it that rely on it. +// +// Users of glslang should call shFinalize() or glslang::FinalizeProcess() for +// process-scoped memory tear down. +bool DetachProcess() +{ + bool success = true; + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) + return true; + + success = DetachThread(); + + OS_FreeTLSIndex(ThreadInitializeIndex); + ThreadInitializeIndex = OS_INVALID_TLS_INDEX; + + return success; +} + } // end namespace glslang diff --git a/3rdparty/bgfx/3rdparty/glslang/OGLCompilersDLL/InitializeDll.h b/3rdparty/bgfx/3rdparty/glslang/OGLCompilersDLL/InitializeDll.h index b18e2ab3c5b..661cee4d240 100644 --- a/3rdparty/bgfx/3rdparty/glslang/OGLCompilersDLL/InitializeDll.h +++ b/3rdparty/bgfx/3rdparty/glslang/OGLCompilersDLL/InitializeDll.h @@ -38,10 +38,10 @@ namespace glslang { -inline bool InitProcess() { return true; } // DEPRECATED -inline bool InitThread() { return true; } // DEPRECATED -inline bool DetachThread() { return true; } // DEPRECATED -inline bool DetachProcess() { return true; } // DEPRECATED +bool InitProcess(); +bool InitThread(); +bool DetachThread(); // not called from standalone, perhaps other tools rely on parts of it +bool DetachProcess(); // not called from standalone, perhaps other tools rely on parts of it } // end namespace glslang diff --git a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.ARM.h b/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.ARM.h deleted file mode 100644 index 14425be1e3e..00000000000 --- a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.ARM.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -** Copyright (c) 2022 ARM Limited -** -** Permission is hereby granted, free of charge, to any person obtaining a copy -** of this software and/or associated documentation files (the "Materials"), -** to deal in the Materials without restriction, including without limitation -** the rights to use, copy, modify, merge, publish, distribute, sublicense, -** and/or sell copies of the Materials, and to permit persons to whom the -** Materials are furnished to do so, subject to the following conditions: -** -** The above copyright notice and this permission notice shall be included in -** all copies or substantial portions of the Materials. -** -** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS -** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS -** IN THE MATERIALS. -*/ - -#ifndef GLSLextARM_H -#define GLSLextARM_H - -static const int GLSLextARMVersion = 100; -static const int GLSLextARMRevision = 1; - -static const char * const E_SPV_ARM_core_builtins = "SPV_ARM_core_builtins"; - -#endif // #ifndef GLSLextARM_H diff --git a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.EXT.h b/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.EXT.h index caab2793823..a247b4cd131 100644 --- a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.EXT.h +++ b/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.EXT.h @@ -39,7 +39,6 @@ static const char* const E_SPV_EXT_shader_atomic_float_add = "SPV_EXT_shader_ato static const char* const E_SPV_EXT_shader_atomic_float16_add = "SPV_EXT_shader_atomic_float16_add"; static const char* const E_SPV_EXT_shader_atomic_float_min_max = "SPV_EXT_shader_atomic_float_min_max"; static const char* const E_SPV_EXT_shader_image_int64 = "SPV_EXT_shader_image_int64"; -static const char* const E_SPV_EXT_shader_tile_image = "SPV_EXT_shader_tile_image"; static const char* const E_SPV_EXT_mesh_shader = "SPV_EXT_mesh_shader"; #endif // #ifndef GLSLextEXT_H diff --git a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.KHR.h b/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.KHR.h index 121defa16a2..d5c670f0e12 100644 --- a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.KHR.h +++ b/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.KHR.h @@ -54,7 +54,5 @@ static const char* const E_SPV_KHR_workgroup_memory_explicit_layout = "SPV_KHR_w static const char* const E_SPV_KHR_subgroup_uniform_control_flow = "SPV_KHR_subgroup_uniform_control_flow"; static const char* const E_SPV_KHR_fragment_shader_barycentric = "SPV_KHR_fragment_shader_barycentric"; static const char* const E_SPV_AMD_shader_early_and_late_fragment_tests = "SPV_AMD_shader_early_and_late_fragment_tests"; -static const char* const E_SPV_KHR_ray_tracing_position_fetch = "SPV_KHR_ray_tracing_position_fetch"; -static const char* const E_SPV_KHR_cooperative_matrix = "SPV_KHR_cooperative_matrix"; #endif // #ifndef GLSLextKHR_H diff --git a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.NV.h b/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.NV.h index 5b0f7eb17e3..93c98bf6269 100644 --- a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.NV.h +++ b/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.ext.NV.h @@ -81,7 +81,4 @@ const char* const E_SPV_NV_cooperative_matrix = "SPV_NV_cooperative_matrix"; //SPV_NV_shader_sm_builtins const char* const E_SPV_NV_shader_sm_builtins = "SPV_NV_shader_sm_builtins"; -//SPV_NV_shader_execution_reorder -const char* const E_SPV_NV_shader_invocation_reorder = "SPV_NV_shader_invocation_reorder"; - #endif // #ifndef GLSLextNV_H diff --git a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.std.450.h b/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.std.450.h index 86d3da80654..df31092bec0 100644 --- a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.std.450.h +++ b/3rdparty/bgfx/3rdparty/glslang/SPIRV/GLSL.std.450.h @@ -13,7 +13,7 @@ ** ** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS ** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, diff --git a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GlslangToSpv.cpp b/3rdparty/bgfx/3rdparty/glslang/SPIRV/GlslangToSpv.cpp old mode 100755 new mode 100644 index 71ce52b4245..842221cba0d --- a/3rdparty/bgfx/3rdparty/glslang/SPIRV/GlslangToSpv.cpp +++ b/3rdparty/bgfx/3rdparty/glslang/SPIRV/GlslangToSpv.cpp @@ -49,7 +49,6 @@ namespace spv { #include "GLSL.ext.EXT.h" #include "GLSL.ext.AMD.h" #include "GLSL.ext.NV.h" - #include "GLSL.ext.ARM.h" #include "NonSemanticDebugPrintf.h" } @@ -95,18 +94,26 @@ struct OpDecorations { public: OpDecorations(spv::Decoration precision, spv::Decoration noContraction, spv::Decoration nonUniform) : precision(precision) +#ifndef GLSLANG_WEB , noContraction(noContraction), nonUniform(nonUniform) +#endif { } spv::Decoration precision; +#ifdef GLSLANG_WEB + void addNoContraction(spv::Builder&, spv::Id) const { } + void addNonUniform(spv::Builder&, spv::Id) const { } +#else void addNoContraction(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, noContraction); } void addNonUniform(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, nonUniform); } protected: spv::Decoration noContraction; spv::Decoration nonUniform; +#endif + }; } // namespace @@ -167,8 +174,8 @@ protected: spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking, const glslang::TQualifier&); void decorateStructType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking, - const glslang::TQualifier&, spv::Id, const std::vector& spvMembers); - spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim, bool allowZero = false); + const glslang::TQualifier&, spv::Id); + spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim); spv::Id accessChainLoad(const glslang::TType& type); void accessChainStore(const glslang::TType& type, spv::Id rvalue); void multiTypeStore(const glslang::TType&, spv::Id rValue); @@ -204,7 +211,7 @@ protected: glslang::TBasicType typeProxy); spv::Id createConversion(glslang::TOperator op, OpDecorations&, spv::Id destTypeId, spv::Id operand, glslang::TBasicType typeProxy); - spv::Id createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize, spv::Id destType); + spv::Id createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize); spv::Id makeSmearedConstant(spv::Id constant, int vectorSize); spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy, @@ -270,10 +277,12 @@ protected: // requiring local translation to and from SPIR-V type on every access. // Maps AST-required-type-id> std::unordered_map forceType; + + // Used later for generating OpTraceKHR/OpExecuteCallableKHR + std::unordered_map locationToSymbol[2]; + // Used by Task shader while generating opearnds for OpEmitMeshTasksEXT spv::Id taskPayloadID; - // Used later for generating OpTraceKHR/OpExecuteCallableKHR/OpHitObjectRecordHit*/OpHitObjectGetShaderBindingTableData - std::unordered_map locationToSymbol[4]; }; // @@ -283,6 +292,10 @@ protected: // Translate glslang profile to SPIR-V source language. spv::SourceLanguage TranslateSourceLanguage(glslang::EShSource source, EProfile profile) { +#ifdef GLSLANG_WEB + return spv::SourceLanguageESSL; +#endif + switch (source) { case glslang::EShSourceGlsl: switch (profile) { @@ -309,6 +322,7 @@ spv::ExecutionModel TranslateExecutionModel(EShLanguage stage, bool isMeshShader case EShLangVertex: return spv::ExecutionModelVertex; case EShLangFragment: return spv::ExecutionModelFragment; case EShLangCompute: return spv::ExecutionModelGLCompute; +#ifndef GLSLANG_WEB case EShLangTessControl: return spv::ExecutionModelTessellationControl; case EShLangTessEvaluation: return spv::ExecutionModelTessellationEvaluation; case EShLangGeometry: return spv::ExecutionModelGeometry; @@ -320,6 +334,7 @@ spv::ExecutionModel TranslateExecutionModel(EShLanguage stage, bool isMeshShader case EShLangCallable: return spv::ExecutionModelCallableKHR; case EShLangTask: return (isMeshShaderEXT)? spv::ExecutionModelTaskEXT : spv::ExecutionModelTaskNV; case EShLangMesh: return (isMeshShaderEXT)? spv::ExecutionModelMeshEXT: spv::ExecutionModelMeshNV; +#endif default: assert(0); return spv::ExecutionModelFragment; @@ -337,7 +352,6 @@ spv::Dim TranslateDimensionality(const glslang::TSampler& sampler) case glslang::EsdRect: return spv::DimRect; case glslang::EsdBuffer: return spv::DimBuffer; case glslang::EsdSubpass: return spv::DimSubpassData; - case glslang::EsdAttachmentEXT: return spv::DimTileImageDataEXT; default: assert(0); return spv::Dim2D; @@ -362,23 +376,26 @@ spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type) } // Translate glslang type to SPIR-V block decorations. -spv::Decoration TranslateBlockDecoration(const glslang::TStorageQualifier storage, bool useStorageBuffer) +spv::Decoration TranslateBlockDecoration(const glslang::TType& type, bool useStorageBuffer) { - switch (storage) { - case glslang::EvqUniform: return spv::DecorationBlock; - case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock; - case glslang::EvqVaryingIn: return spv::DecorationBlock; - case glslang::EvqVaryingOut: return spv::DecorationBlock; - case glslang::EvqShared: return spv::DecorationBlock; - case glslang::EvqPayload: return spv::DecorationBlock; - case glslang::EvqPayloadIn: return spv::DecorationBlock; - case glslang::EvqHitAttr: return spv::DecorationBlock; - case glslang::EvqCallableData: return spv::DecorationBlock; - case glslang::EvqCallableDataIn: return spv::DecorationBlock; - case glslang::EvqHitObjectAttrNV: return spv::DecorationBlock; - default: - assert(0); - break; + if (type.getBasicType() == glslang::EbtBlock) { + switch (type.getQualifier().storage) { + case glslang::EvqUniform: return spv::DecorationBlock; + case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock; + case glslang::EvqVaryingIn: return spv::DecorationBlock; + case glslang::EvqVaryingOut: return spv::DecorationBlock; + case glslang::EvqShared: return spv::DecorationBlock; +#ifndef GLSLANG_WEB + case glslang::EvqPayload: return spv::DecorationBlock; + case glslang::EvqPayloadIn: return spv::DecorationBlock; + case glslang::EvqHitAttr: return spv::DecorationBlock; + case glslang::EvqCallableData: return spv::DecorationBlock; + case glslang::EvqCallableDataIn: return spv::DecorationBlock; +#endif + default: + assert(0); + break; + } } return spv::DecorationMax; @@ -445,13 +462,14 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::T assert(type.getQualifier().layoutPacking == glslang::ElpNone); } return spv::DecorationMax; +#ifndef GLSLANG_WEB case glslang::EvqPayload: case glslang::EvqPayloadIn: case glslang::EvqHitAttr: case glslang::EvqCallableData: case glslang::EvqCallableDataIn: - case glslang::EvqHitObjectAttrNV: return spv::DecorationMax; +#endif default: assert(0); return spv::DecorationMax; @@ -487,12 +505,14 @@ spv::Decoration TGlslangToSpvTraverser::TranslateAuxiliaryStorageDecoration(cons { if (qualifier.centroid) return spv::DecorationCentroid; +#ifndef GLSLANG_WEB else if (qualifier.patch) return spv::DecorationPatch; else if (qualifier.sample) { builder.addCapability(spv::CapabilitySampleRateShading); return spv::DecorationSample; } +#endif return spv::DecorationMax; } @@ -509,20 +529,24 @@ spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifie // If glslang type is noContraction, return SPIR-V NoContraction decoration. spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier) { +#ifndef GLSLANG_WEB if (qualifier.isNoContraction()) return spv::DecorationNoContraction; else +#endif return spv::DecorationMax; } // If glslang type is nonUniform, return SPIR-V NonUniform decoration. spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glslang::TQualifier& qualifier) { +#ifndef GLSLANG_WEB if (qualifier.isNonUniform()) { builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5); builder.addCapability(spv::CapabilityShaderNonUniformEXT); return spv::DecorationNonUniformEXT; } else +#endif return spv::DecorationMax; } @@ -530,11 +554,13 @@ spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glsl spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration( const spv::Builder::AccessChain::CoherentFlags& coherentFlags) { +#ifndef GLSLANG_WEB if (coherentFlags.isNonUniform()) { builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5); builder.addCapability(spv::CapabilityShaderNonUniformEXT); return spv::DecorationNonUniformEXT; } else +#endif return spv::DecorationMax; } @@ -543,6 +569,7 @@ spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess( { spv::MemoryAccessMask mask = spv::MemoryAccessMaskNone; +#ifndef GLSLANG_WEB if (!glslangIntermediate->usingVulkanMemoryModel() || coherentFlags.isImage) return mask; @@ -560,6 +587,7 @@ spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess( if (mask != spv::MemoryAccessMaskNone) { builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); } +#endif return mask; } @@ -569,6 +597,7 @@ spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands( { spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone; +#ifndef GLSLANG_WEB if (!glslangIntermediate->usingVulkanMemoryModel()) return mask; @@ -586,6 +615,7 @@ spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands( if (mask != spv::ImageOperandsMaskNone) { builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); } +#endif return mask; } @@ -593,6 +623,7 @@ spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands( spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCoherent(const glslang::TType& type) { spv::Builder::AccessChain::CoherentFlags flags = {}; +#ifndef GLSLANG_WEB flags.coherent = type.getQualifier().coherent; flags.devicecoherent = type.getQualifier().devicecoherent; flags.queuefamilycoherent = type.getQualifier().queuefamilycoherent; @@ -607,6 +638,7 @@ spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCohere flags.anyCoherent() || flags.volatil; flags.isImage = type.getBasicType() == glslang::EbtSampler; +#endif flags.nonUniform = type.getQualifier().nonUniform; return flags; } @@ -616,6 +648,7 @@ spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope( { spv::Scope scope = spv::ScopeMax; +#ifndef GLSLANG_WEB if (coherentFlags.volatil || coherentFlags.coherent) { // coherent defaults to Device scope in the old model, QueueFamilyKHR scope in the new model scope = glslangIntermediate->usingVulkanMemoryModel() ? spv::ScopeQueueFamilyKHR : spv::ScopeDevice; @@ -633,6 +666,7 @@ spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope( if (glslangIntermediate->usingVulkanMemoryModel() && scope == spv::ScopeDevice) { builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR); } +#endif return scope; } @@ -647,6 +681,7 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI { switch (builtIn) { case glslang::EbvPointSize: +#ifndef GLSLANG_WEB // Defer adding the capability until the built-in is actually used. if (! memberDeclaration) { switch (glslangIntermediate->getStage()) { @@ -661,6 +696,7 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI break; } } +#endif return spv::BuiltInPointSize; case glslang::EbvPosition: return spv::BuiltInPosition; @@ -681,6 +717,7 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex; case glslang::EbvGlobalInvocationId: return spv::BuiltInGlobalInvocationId; +#ifndef GLSLANG_WEB // These *Distance capabilities logically belong here, but if the member is declared and // then never used, consumers of SPIR-V prefer the capability not be declared. // They are now generated when used, rather than here when declared. @@ -974,8 +1011,6 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI return spv::BuiltInRayTmaxKHR; case glslang::EbvCullMask: return spv::BuiltInCullMaskKHR; - case glslang::EbvPositionFetch: - return spv::BuiltInHitTriangleVertexPositionsKHR; case glslang::EbvInstanceCustomIndex: return spv::BuiltInInstanceCustomIndexKHR; case glslang::EbvHitT: @@ -1071,28 +1106,7 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI builder.addExtension(spv::E_SPV_NV_shader_sm_builtins); builder.addCapability(spv::CapabilityShaderSMBuiltinsNV); return spv::BuiltInSMIDNV; - - // ARM builtins - case glslang::EbvCoreCountARM: - builder.addExtension(spv::E_SPV_ARM_core_builtins); - builder.addCapability(spv::CapabilityCoreBuiltinsARM); - return spv::BuiltInCoreCountARM; - case glslang::EbvCoreIDARM: - builder.addExtension(spv::E_SPV_ARM_core_builtins); - builder.addCapability(spv::CapabilityCoreBuiltinsARM); - return spv::BuiltInCoreIDARM; - case glslang::EbvCoreMaxIDARM: - builder.addExtension(spv::E_SPV_ARM_core_builtins); - builder.addCapability(spv::CapabilityCoreBuiltinsARM); - return spv::BuiltInCoreMaxIDARM; - case glslang::EbvWarpIDARM: - builder.addExtension(spv::E_SPV_ARM_core_builtins); - builder.addCapability(spv::CapabilityCoreBuiltinsARM); - return spv::BuiltInWarpIDARM; - case glslang::EbvWarpMaxIDARM: - builder.addExtension(spv::E_SPV_ARM_core_builtins); - builder.addCapability(spv::CapabilityCoreBuiltinsARM); - return spv::BuiltInWarpMaxIDARM; +#endif default: return spv::BuiltInMax; @@ -1104,6 +1118,10 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy { assert(type.getBasicType() == glslang::EbtSampler); +#ifdef GLSLANG_WEB + return spv::ImageFormatUnknown; +#endif + // Check for capabilities switch (type.getQualifier().getFormat()) { case glslang::ElfRg32f: @@ -1258,27 +1276,24 @@ spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang: // Translate glslang type to SPIR-V storage class. spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::TType& type) { - if (type.getBasicType() == glslang::EbtRayQuery || type.getBasicType() == glslang::EbtHitObjectNV) + if (type.getBasicType() == glslang::EbtRayQuery) return spv::StorageClassPrivate; +#ifndef GLSLANG_WEB if (type.getQualifier().isSpirvByReference()) { if (type.getQualifier().isParamInput() || type.getQualifier().isParamOutput()) return spv::StorageClassFunction; } +#endif if (type.getQualifier().isPipeInput()) return spv::StorageClassInput; if (type.getQualifier().isPipeOutput()) return spv::StorageClassOutput; - if (type.getQualifier().storage == glslang::EvqTileImageEXT || type.isAttachmentEXT()) { - builder.addExtension(spv::E_SPV_EXT_shader_tile_image); - builder.addCapability(spv::CapabilityTileImageColorReadAccessEXT); - return spv::StorageClassTileImageEXT; - } if (glslangIntermediate->getSource() != glslang::EShSourceHlsl || type.getQualifier().storage == glslang::EvqUniform) { if (type.isAtomic()) return spv::StorageClassAtomicCounter; - if (type.containsOpaque() && !glslangIntermediate->getBindlessMode()) + if (type.containsOpaque()) return spv::StorageClassUniformConstant; } @@ -1311,14 +1326,15 @@ spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::T case glslang::EvqConstReadOnly: return spv::StorageClassFunction; case glslang::EvqTemporary: return spv::StorageClassFunction; case glslang::EvqShared: return spv::StorageClassWorkgroup; +#ifndef GLSLANG_WEB case glslang::EvqPayload: return spv::StorageClassRayPayloadKHR; case glslang::EvqPayloadIn: return spv::StorageClassIncomingRayPayloadKHR; case glslang::EvqHitAttr: return spv::StorageClassHitAttributeKHR; case glslang::EvqCallableData: return spv::StorageClassCallableDataKHR; case glslang::EvqCallableDataIn: return spv::StorageClassIncomingCallableDataKHR; case glslang::EvqtaskPayloadSharedEXT : return spv::StorageClassTaskPayloadWorkgroupEXT; - case glslang::EvqHitObjectAttrNV: return spv::StorageClassHitObjectAttributeNV; case glslang::EvqSpirvStorageClass: return static_cast(type.getQualifier().spirvStorageClass); +#endif default: assert(0); break; @@ -1379,6 +1395,7 @@ void TGlslangToSpvTraverser::TranslateLiterals(const glslang::TVectorgetSource(), glslangIntermediate->getProfile()), glslangIntermediate->getVersion()); - if (options.emitNonSemanticShaderDebugSource) - this->options.emitNonSemanticShaderDebugInfo = true; - if (options.emitNonSemanticShaderDebugInfo) - this->options.generateDebugInfo = true; - - if (this->options.generateDebugInfo) { + if (options.generateDebugInfo) { builder.setEmitOpLines(); builder.setSourceFile(glslangIntermediate->getSourceFile()); @@ -1562,8 +1577,8 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addInclude(iItr->first, iItr->second); } - builder.setEmitNonSemanticShaderDebugInfo(this->options.emitNonSemanticShaderDebugInfo); - builder.setEmitNonSemanticShaderDebugSource(this->options.emitNonSemanticShaderDebugSource); + builder.setEmitNonSemanticShaderDebugInfo(options.emitNonSemanticShaderDebugInfo); + builder.setEmitNonSemanticShaderDebugSource(options.emitNonSemanticShaderDebugSource); stdBuiltins = builder.import("GLSL.std.450"); @@ -1605,10 +1620,12 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addCapability(spv::CapabilityRayTraversalPrimitiveCullingKHR); } +#ifndef GLSLANG_WEB if (glslangIntermediate->getSubgroupUniformControlFlow()) { builder.addExtension(spv::E_SPV_KHR_subgroup_uniform_control_flow); builder.addExecutionMode(shaderEntry, spv::ExecutionModeSubgroupUniformControlFlowKHR); } +#endif unsigned int mode; switch (glslangIntermediate->getStage()) { @@ -1641,30 +1658,14 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addExtension(spv::E_SPV_KHR_post_depth_coverage); } - if (glslangIntermediate->getNonCoherentColorAttachmentReadEXT()) { - builder.addCapability(spv::CapabilityTileImageColorReadAccessEXT); - builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentColorAttachmentReadEXT); - builder.addExtension(spv::E_SPV_EXT_shader_tile_image); - } - - if (glslangIntermediate->getNonCoherentDepthAttachmentReadEXT()) { - builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT); - builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentDepthAttachmentReadEXT); - builder.addExtension(spv::E_SPV_EXT_shader_tile_image); - } - - if (glslangIntermediate->getNonCoherentStencilAttachmentReadEXT()) { - builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT); - builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentStencilAttachmentReadEXT); - builder.addExtension(spv::E_SPV_EXT_shader_tile_image); - } - if (glslangIntermediate->isDepthReplacing()) builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing); if (glslangIntermediate->isStencilReplacing()) builder.addExecutionMode(shaderEntry, spv::ExecutionModeStencilRefReplacingEXT); +#ifndef GLSLANG_WEB + switch(glslangIntermediate->getDepth()) { case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break; case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break; @@ -1716,6 +1717,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, } builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock); } +#endif break; case EShLangCompute: @@ -1746,6 +1748,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives); } break; +#ifndef GLSLANG_WEB case EShLangTessEvaluation: case EShLangTessControl: builder.addCapability(spv::CapabilityTessellation); @@ -1832,16 +1835,13 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addCapability(spv::CapabilityRayTracingNV); builder.addExtension("SPV_NV_ray_tracing"); } - if (glslangIntermediate->getStage() != EShLangRayGen && glslangIntermediate->getStage() != EShLangCallable) { - if (extensions.find("GL_EXT_ray_cull_mask") != extensions.end()) { - builder.addCapability(spv::CapabilityRayCullMaskKHR); - builder.addExtension("SPV_KHR_ray_cull_mask"); - } - if (extensions.find("GL_EXT_ray_tracing_position_fetch") != extensions.end()) { - builder.addCapability(spv::CapabilityRayTracingPositionFetchKHR); - builder.addExtension("SPV_KHR_ray_tracing_position_fetch"); - } - } + if (glslangIntermediate->getStage() != EShLangRayGen && glslangIntermediate->getStage() != EShLangCallable) + { + if (extensions.find("GL_EXT_ray_cull_mask") != extensions.end()) { + builder.addCapability(spv::CapabilityRayCullMaskKHR); + builder.addExtension("SPV_KHR_ray_cull_mask"); + } + } break; } case EShLangTask: @@ -1885,11 +1885,13 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); } break; +#endif default: break; } +#ifndef GLSLANG_WEB // // Add SPIR-V requirements (GL_EXT_spirv_intrinsics) // @@ -1934,6 +1936,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addExecutionModeId(shaderEntry, static_cast(modeId.first), operandIds); } } +#endif } // Finish creating SPV, after the traversal is complete. @@ -1979,10 +1982,6 @@ void TGlslangToSpvTraverser::dumpSpv(std::vector& out) // void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) { - // We update the line information even though no code might be generated here - // This is helpful to yield correct lines for control flow instructions - builder.setLine(symbol->getLoc().line, symbol->getLoc().getFilename()); - SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); if (symbol->getType().isStruct()) glslangTypeToIdMap[symbol->getType().getStruct()] = symbol->getId(); @@ -2134,9 +2133,6 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T node->getRight()->traverse(this); spv::Id rValue = accessChainLoad(node->getRight()->getType()); - // reset line number for assignment - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); - if (node->getOp() != glslang::EOpAssign) { // the left is also an r-value builder.setAccessChain(lValue); @@ -2501,15 +2497,12 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI spv::Id length; if (node->getOperand()->getType().isCoopMat()) { + spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); + spv::Id typeId = convertGlslangToSpvType(node->getOperand()->getType()); assert(builder.isCooperativeMatrixType(typeId)); - if (node->getOperand()->getType().isCoopMatKHR()) { - length = builder.createCooperativeMatrixLengthKHR(typeId); - } else { - spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); - length = builder.createCooperativeMatrixLengthNV(typeId); - } + length = builder.createCooperativeMatrixLength(typeId); } else { glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft(); block->traverse(this); @@ -2566,35 +2559,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags; - const auto hitObjectOpsWithLvalue = [](glslang::TOperator op) { - switch(op) { - case glslang::EOpReorderThreadNV: - case glslang::EOpHitObjectGetCurrentTimeNV: - case glslang::EOpHitObjectGetHitKindNV: - case glslang::EOpHitObjectGetPrimitiveIndexNV: - case glslang::EOpHitObjectGetGeometryIndexNV: - case glslang::EOpHitObjectGetInstanceIdNV: - case glslang::EOpHitObjectGetInstanceCustomIndexNV: - case glslang::EOpHitObjectGetObjectRayDirectionNV: - case glslang::EOpHitObjectGetObjectRayOriginNV: - case glslang::EOpHitObjectGetWorldRayDirectionNV: - case glslang::EOpHitObjectGetWorldRayOriginNV: - case glslang::EOpHitObjectGetWorldToObjectNV: - case glslang::EOpHitObjectGetObjectToWorldNV: - case glslang::EOpHitObjectGetRayTMaxNV: - case glslang::EOpHitObjectGetRayTMinNV: - case glslang::EOpHitObjectIsEmptyNV: - case glslang::EOpHitObjectIsHitNV: - case glslang::EOpHitObjectIsMissNV: - case glslang::EOpHitObjectRecordEmptyNV: - case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV: - case glslang::EOpHitObjectGetShaderRecordBufferHandleNV: - return true; - default: - return false; - } - }; - +#ifndef GLSLANG_WEB if (node->getOp() == glslang::EOpAtomicCounterIncrement || node->getOp() == glslang::EOpAtomicCounterDecrement || node->getOp() == glslang::EOpAtomicCounter || @@ -2608,15 +2573,16 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI node->getOp() == glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque || node->getOp() == glslang::EOpRayQueryTerminate || node->getOp() == glslang::EOpRayQueryConfirmIntersection || - (node->getOp() == glslang::EOpSpirvInst && operandNode->getAsTyped()->getQualifier().isSpirvByReference()) || - hitObjectOpsWithLvalue(node->getOp())) { + (node->getOp() == glslang::EOpSpirvInst && operandNode->getAsTyped()->getQualifier().isSpirvByReference())) { operand = builder.accessChainGetLValue(); // Special case l-value operands lvalueCoherentFlags = builder.getAccessChain().coherentFlags; lvalueCoherentFlags |= TranslateCoherent(operandNode->getAsTyped()->getType()); } else if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) { // Will be translated to a literal value, make a placeholder here operand = spv::NoResult; - } else { + } else +#endif + { operand = accessChainLoad(node->getOperand()->getType()); } @@ -2634,6 +2600,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI result = createUnaryOperation(node->getOp(), decorations, resultType(), operand, node->getOperand()->getBasicType(), lvalueCoherentFlags); +#ifndef GLSLANG_WEB // it could be attached to a SPIR-V intruction if (!result) { if (node->getOp() == glslang::EOpSpirvInst) { @@ -2663,6 +2630,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI return false; // done with this node } } +#endif if (result) { if (invertedType) { @@ -2687,6 +2655,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI spv::Id one = 0; if (node->getBasicType() == glslang::EbtFloat) one = builder.makeFloatConstant(1.0F); +#ifndef GLSLANG_WEB else if (node->getBasicType() == glslang::EbtDouble) one = builder.makeDoubleConstant(1.0); else if (node->getBasicType() == glslang::EbtFloat16) @@ -2697,6 +2666,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI one = builder.makeInt16Constant(1); else if (node->getBasicType() == glslang::EbtInt64 || node->getBasicType() == glslang::EbtUint64) one = builder.makeInt64Constant(1); +#endif else one = builder.makeIntConstant(1); glslang::TOperator op; @@ -2725,6 +2695,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI return false; +#ifndef GLSLANG_WEB case glslang::EOpEmitStreamVertex: builder.createNoResultOp(spv::OpEmitStreamVertex, operand); return false; @@ -2737,12 +2708,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI case glslang::EOpRayQueryConfirmIntersection: builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR, operand); return false; - case glslang::EOpReorderThreadNV: - builder.createNoResultOp(spv::OpReorderThreadWithHitObjectNV, operand); - return false; - case glslang::EOpHitObjectRecordEmptyNV: - builder.createNoResultOp(spv::OpHitObjectRecordEmptyNV, operand); - return false; +#endif default: logger->missingFunctionality("unknown glslang unary"); @@ -2807,12 +2773,15 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt builder.setAccessChainRValue(result); return false; - } else if (node->getOp() == glslang::EOpImageStore || + } +#ifndef GLSLANG_WEB + else if (node->getOp() == glslang::EOpImageStore || node->getOp() == glslang::EOpImageStoreLod || node->getOp() == glslang::EOpImageAtomicStore) { // "imageStore" is a special case, which has no result return false; } +#endif glslang::TOperator binOp = glslang::EOpNull; bool reduceComparison = true; @@ -3031,8 +3000,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpConstructStruct: case glslang::EOpConstructTextureSampler: case glslang::EOpConstructReference: - case glslang::EOpConstructCooperativeMatrixNV: - case glslang::EOpConstructCooperativeMatrixKHR: + case glslang::EOpConstructCooperativeMatrix: { builder.setLine(node->getLoc().line, node->getLoc().getFilename()); std::vector arguments; @@ -3049,8 +3017,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt } else constructed = builder.createOp(spv::OpSampledImage, resultType(), arguments); } else if (node->getOp() == glslang::EOpConstructStruct || - node->getOp() == glslang::EOpConstructCooperativeMatrixNV || - node->getOp() == glslang::EOpConstructCooperativeMatrixKHR || + node->getOp() == glslang::EOpConstructCooperativeMatrix || node->getType().isArray()) { std::vector constituents; for (int c = 0; c < (int)arguments.size(); ++c) @@ -3148,6 +3115,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt atomic = true; break; +#ifndef GLSLANG_WEB case glslang::EOpAtomicStore: noReturnValue = true; // fallthrough @@ -3224,8 +3192,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; case glslang::EOpCooperativeMatrixLoad: case glslang::EOpCooperativeMatrixStore: - case glslang::EOpCooperativeMatrixLoadNV: - case glslang::EOpCooperativeMatrixStoreNV: noReturnValue = true; break; case glslang::EOpBeginInvocationInterlock: @@ -3233,48 +3199,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock); noReturnValue = true; break; - - case glslang::EOpHitObjectTraceRayNV: - case glslang::EOpHitObjectTraceRayMotionNV: - case glslang::EOpHitObjectGetAttributesNV: - case glslang::EOpHitObjectExecuteShaderNV: - case glslang::EOpHitObjectRecordEmptyNV: - case glslang::EOpHitObjectRecordMissNV: - case glslang::EOpHitObjectRecordMissMotionNV: - case glslang::EOpHitObjectRecordHitNV: - case glslang::EOpHitObjectRecordHitMotionNV: - case glslang::EOpHitObjectRecordHitWithIndexNV: - case glslang::EOpHitObjectRecordHitWithIndexMotionNV: - case glslang::EOpReorderThreadNV: - noReturnValue = true; - //Fallthrough - case glslang::EOpHitObjectIsEmptyNV: - case glslang::EOpHitObjectIsMissNV: - case glslang::EOpHitObjectIsHitNV: - case glslang::EOpHitObjectGetRayTMinNV: - case glslang::EOpHitObjectGetRayTMaxNV: - case glslang::EOpHitObjectGetObjectRayOriginNV: - case glslang::EOpHitObjectGetObjectRayDirectionNV: - case glslang::EOpHitObjectGetWorldRayOriginNV: - case glslang::EOpHitObjectGetWorldRayDirectionNV: - case glslang::EOpHitObjectGetObjectToWorldNV: - case glslang::EOpHitObjectGetWorldToObjectNV: - case glslang::EOpHitObjectGetInstanceCustomIndexNV: - case glslang::EOpHitObjectGetInstanceIdNV: - case glslang::EOpHitObjectGetGeometryIndexNV: - case glslang::EOpHitObjectGetPrimitiveIndexNV: - case glslang::EOpHitObjectGetHitKindNV: - case glslang::EOpHitObjectGetCurrentTimeNV: - case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV: - case glslang::EOpHitObjectGetShaderRecordBufferHandleNV: - builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder); - builder.addCapability(spv::CapabilityShaderInvocationReorderNV); - break; - case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT: - builder.addExtension(spv::E_SPV_KHR_ray_tracing_position_fetch); - builder.addCapability(spv::CapabilityRayQueryPositionFetchKHR); - noReturnValue = true; - break; +#endif case glslang::EOpDebugPrintf: noReturnValue = true; @@ -3331,22 +3256,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt lvalue = true; break; - - - case glslang::EOpHitObjectRecordHitNV: - case glslang::EOpHitObjectRecordHitMotionNV: - case glslang::EOpHitObjectRecordHitWithIndexNV: - case glslang::EOpHitObjectRecordHitWithIndexMotionNV: - case glslang::EOpHitObjectTraceRayNV: - case glslang::EOpHitObjectTraceRayMotionNV: - case glslang::EOpHitObjectExecuteShaderNV: - case glslang::EOpHitObjectRecordMissNV: - case glslang::EOpHitObjectRecordMissMotionNV: - case glslang::EOpHitObjectGetAttributesNV: - if (arg == 0) - lvalue = true; - break; - case glslang::EOpRayQueryInitialize: case glslang::EOpRayQueryTerminate: case glslang::EOpRayQueryConfirmIntersection: @@ -3382,6 +3291,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt lvalue = true; break; +#ifndef GLSLANG_WEB case glslang::EOpFrexp: if (arg == 1) lvalue = true; @@ -3435,12 +3345,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt lvalue = true; break; case glslang::EOpCooperativeMatrixLoad: - case glslang::EOpCooperativeMatrixLoadNV: if (arg == 0 || arg == 1) lvalue = true; break; case glslang::EOpCooperativeMatrixStore: - case glslang::EOpCooperativeMatrixStoreNV: if (arg == 1) lvalue = true; break; @@ -3448,15 +3356,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvByReference()) lvalue = true; break; - case glslang::EOpReorderThreadNV: - //Three variants of reorderThreadNV, two of them use hitObjectNV - if (arg == 0 && glslangOperands.size() != 2) - lvalue = true; - break; - case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT: - if (arg == 0 || arg == 2) - lvalue = true; - break; +#endif default: break; } @@ -3466,10 +3366,9 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt else glslangOperands[arg]->traverse(this); +#ifndef GLSLANG_WEB if (node->getOp() == glslang::EOpCooperativeMatrixLoad || - node->getOp() == glslang::EOpCooperativeMatrixStore || - node->getOp() == glslang::EOpCooperativeMatrixLoadNV || - node->getOp() == glslang::EOpCooperativeMatrixStoreNV) { + node->getOp() == glslang::EOpCooperativeMatrixStore) { if (arg == 1) { // fold "element" parameter into the access chain @@ -3490,11 +3389,9 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt unsigned int alignment = builder.getAccessChain().alignment; int memoryAccess = TranslateMemoryAccess(coherentFlags); - if (node->getOp() == glslang::EOpCooperativeMatrixLoad || - node->getOp() == glslang::EOpCooperativeMatrixLoadNV) + if (node->getOp() == glslang::EOpCooperativeMatrixLoad) memoryAccess &= ~spv::MemoryAccessMakePointerAvailableKHRMask; - if (node->getOp() == glslang::EOpCooperativeMatrixStore || - node->getOp() == glslang::EOpCooperativeMatrixStoreNV) + if (node->getOp() == glslang::EOpCooperativeMatrixStore) memoryAccess &= ~spv::MemoryAccessMakePointerVisibleKHRMask; if (builder.getStorageClass(builder.getAccessChain().base) == spv::StorageClassPhysicalStorageBufferEXT) { @@ -3516,6 +3413,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt continue; } } +#endif // for l-values, pass the address, for r-values, pass the value if (lvalue) { @@ -3550,37 +3448,26 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayDirection || glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayOrigin || glslangOp == glslang::EOpRayQueryGetIntersectionObjectToWorld || - glslangOp == glslang::EOpRayQueryGetIntersectionWorldToObject || - glslangOp == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT + glslangOp == glslang::EOpRayQueryGetIntersectionWorldToObject )) { bool cond = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getBConst(); operands.push_back(builder.makeIntConstant(cond ? 1 : 0)); } else if ((arg == 10 && glslangOp == glslang::EOpTraceKHR) || (arg == 11 && glslangOp == glslang::EOpTraceRayMotionNV) || - (arg == 1 && glslangOp == glslang::EOpExecuteCallableKHR) || - (arg == 1 && glslangOp == glslang::EOpHitObjectExecuteShaderNV) || - (arg == 11 && glslangOp == glslang::EOpHitObjectTraceRayNV) || - (arg == 12 && glslangOp == glslang::EOpHitObjectTraceRayMotionNV)) { + (arg == 1 && glslangOp == glslang::EOpExecuteCallableKHR)) { + const int opdNum = glslangOp == glslang::EOpTraceKHR ? 10 : (glslangOp == glslang::EOpTraceRayMotionNV ? 11 : 1); const int set = glslangOp == glslang::EOpExecuteCallableKHR ? 1 : 0; - const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst(); - auto itNode = locationToSymbol[set].find(location); - visitSymbol(itNode->second); - spv::Id symId = getSymbolId(itNode->second); - operands.push_back(symId); - } else if ((arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitNV) || - (arg == 13 && glslangOp == glslang::EOpHitObjectRecordHitMotionNV) || - (arg == 11 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexNV) || - (arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexMotionNV) || - (arg == 1 && glslangOp == glslang::EOpHitObjectGetAttributesNV)) { - const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst(); - const int set = 2; + + const int location = glslangOperands[opdNum]->getAsConstantUnion()->getConstArray()[0].getUConst(); auto itNode = locationToSymbol[set].find(location); visitSymbol(itNode->second); spv::Id symId = getSymbolId(itNode->second); operands.push_back(symId); +#ifndef GLSLANG_WEB } else if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvLiteral()) { // Will be translated to a literal value, make a placeholder here operands.push_back(spv::NoResult); +#endif } else { operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType())); } @@ -3588,94 +3475,42 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt } builder.setLine(node->getLoc().line, node->getLoc().getFilename()); - if (node->getOp() == glslang::EOpCooperativeMatrixLoad || - node->getOp() == glslang::EOpCooperativeMatrixLoadNV) { +#ifndef GLSLANG_WEB + if (node->getOp() == glslang::EOpCooperativeMatrixLoad) { std::vector idImmOps; idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf - if (node->getOp() == glslang::EOpCooperativeMatrixLoad) { - idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout - idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride - } else { - idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride - idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor - } + idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride + idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end()); // get the pointee type spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0])); assert(builder.isCooperativeMatrixType(typeId)); // do the op - spv::Id result = node->getOp() == glslang::EOpCooperativeMatrixLoad - ? builder.createOp(spv::OpCooperativeMatrixLoadKHR, typeId, idImmOps) - : builder.createOp(spv::OpCooperativeMatrixLoadNV, typeId, idImmOps); + spv::Id result = builder.createOp(spv::OpCooperativeMatrixLoadNV, typeId, idImmOps); // store the result to the pointer (out param 'm') builder.createStore(result, operands[0]); result = 0; - } else if (node->getOp() == glslang::EOpCooperativeMatrixStore || - node->getOp() == glslang::EOpCooperativeMatrixStoreNV) { + } else if (node->getOp() == glslang::EOpCooperativeMatrixStore) { std::vector idImmOps; idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf idImmOps.push_back(spv::IdImmediate(true, operands[0])); // object - if (node->getOp() == glslang::EOpCooperativeMatrixStore) { - idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout - idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride - } else { - idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride - idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor - } + idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride + idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end()); - if (node->getOp() == glslang::EOpCooperativeMatrixStore) - builder.createNoResultOp(spv::OpCooperativeMatrixStoreKHR, idImmOps); - else - builder.createNoResultOp(spv::OpCooperativeMatrixStoreNV, idImmOps); + builder.createNoResultOp(spv::OpCooperativeMatrixStoreNV, idImmOps); result = 0; - } else if (node->getOp() == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT) { - std::vector idImmOps; - - idImmOps.push_back(spv::IdImmediate(true, operands[0])); // q - idImmOps.push_back(spv::IdImmediate(true, operands[1])); // committed - - spv::Id typeId = builder.makeArrayType(builder.makeVectorType(builder.makeFloatType(32), 3), - builder.makeUintConstant(3), 0); - // do the op - spv::Id result = builder.createOp(spv::OpRayQueryGetIntersectionTriangleVertexPositionsKHR, typeId, idImmOps); - // store the result to the pointer (out param 'm') - builder.createStore(result, operands[2]); - result = 0; - } else if (node->getOp() == glslang::EOpCooperativeMatrixMulAdd) { - uint32_t matrixOperands = 0; - - // If the optional operand is present, initialize matrixOperands to that value. - if (glslangOperands.size() == 4 && glslangOperands[3]->getAsConstantUnion()) { - matrixOperands = glslangOperands[3]->getAsConstantUnion()->getConstArray()[0].getIConst(); - } - - // Determine Cooperative Matrix Operands bits from the signedness of the types. - if (isTypeSignedInt(glslangOperands[0]->getAsTyped()->getBasicType())) - matrixOperands |= spv::CooperativeMatrixOperandsMatrixASignedComponentsMask; - if (isTypeSignedInt(glslangOperands[1]->getAsTyped()->getBasicType())) - matrixOperands |= spv::CooperativeMatrixOperandsMatrixBSignedComponentsMask; - if (isTypeSignedInt(glslangOperands[2]->getAsTyped()->getBasicType())) - matrixOperands |= spv::CooperativeMatrixOperandsMatrixCSignedComponentsMask; - if (isTypeSignedInt(node->getBasicType())) - matrixOperands |= spv::CooperativeMatrixOperandsMatrixResultSignedComponentsMask; - - std::vector idImmOps; - idImmOps.push_back(spv::IdImmediate(true, operands[0])); - idImmOps.push_back(spv::IdImmediate(true, operands[1])); - idImmOps.push_back(spv::IdImmediate(true, operands[2])); - if (matrixOperands != 0) - idImmOps.push_back(spv::IdImmediate(false, matrixOperands)); - - result = builder.createOp(spv::OpCooperativeMatrixMulAddKHR, resultType(), idImmOps); - } else if (atomic) { + } else +#endif + if (atomic) { // Handle all atomics glslang::TBasicType typeProxy = (node->getOp() == glslang::EOpAtomicStore) ? node->getSequence()[0]->getAsTyped()->getBasicType() : node->getBasicType(); result = createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy, lvalueCoherentFlags); +#ifndef GLSLANG_WEB } else if (node->getOp() == glslang::EOpSpirvInst) { const auto& spirvInst = node->getSpirvInstruction(); if (spirvInst.set == "") { @@ -3702,6 +3537,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt spirvInst.id, operands); } noReturnValue = node->getBasicType() == glslang::EbtVoid; +#endif } else if (node->getOp() == glslang::EOpDebugPrintf) { if (!nonSemanticDebugPrintf) { nonSemanticDebugPrintf = builder.import("NonSemantic.DebugPrintf"); @@ -3818,11 +3654,10 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang // Find a way of executing both sides and selecting the right result. const auto executeBothSides = [&]() -> void { // execute both sides - spv::Id resultType = convertGlslangToSpvType(node->getType()); node->getTrueBlock()->traverse(this); spv::Id trueValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()); node->getFalseBlock()->traverse(this); - spv::Id falseValue = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()); + spv::Id falseValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()); builder.setLine(node->getLoc().line, node->getLoc().getFilename()); @@ -3831,8 +3666,8 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang return; // emit code to select between trueValue and falseValue - // see if OpSelect can handle the result type, and that the SPIR-V types - // of the inputs match the result type. + + // see if OpSelect can handle it if (isOpSelectable()) { // Emit OpSelect for this selection. @@ -3844,18 +3679,10 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang builder.getNumComponents(trueValue))); } - // If the types do not match, it is because of mismatched decorations on aggregates. - // Since isOpSelectable only lets us get here for SPIR-V >= 1.4, we can use OpCopyObject - // to get matching types. - if (builder.getTypeId(trueValue) != resultType) { - trueValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, trueValue); - } - if (builder.getTypeId(falseValue) != resultType) { - falseValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, falseValue); - } - // OpSelect - result = builder.createTriOp(spv::OpSelect, resultType, condition, trueValue, falseValue); + result = builder.createTriOp(spv::OpSelect, + convertGlslangToSpvType(node->getType()), condition, + trueValue, falseValue); builder.clearAccessChain(); builder.setAccessChainRValue(result); @@ -3863,7 +3690,7 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang // We need control flow to select the result. // TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path. result = builder.createVariable(TranslatePrecisionDecoration(node->getType()), - spv::StorageClassFunction, resultType); + spv::StorageClassFunction, convertGlslangToSpvType(node->getType())); // Selection control: const spv::SelectionControlMask control = TranslateSelectionControl(*node); @@ -3872,15 +3699,10 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang spv::Builder::If ifBuilder(condition, control, builder); // emit the "then" statement - builder.clearAccessChain(); - builder.setAccessChainLValue(result); - multiTypeStore(node->getType(), trueValue); - + builder.createStore(trueValue, result); ifBuilder.makeBeginElse(); // emit the "else" statement - builder.clearAccessChain(); - builder.setAccessChainLValue(result); - multiTypeStore(node->getType(), falseValue); + builder.createStore(falseValue, result); // finish off the control flow ifBuilder.makeEndIf(); @@ -3907,26 +3729,16 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang // emit the "then" statement if (node->getTrueBlock() != nullptr) { node->getTrueBlock()->traverse(this); - if (result != spv::NoResult) { - spv::Id load = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()); - - builder.clearAccessChain(); - builder.setAccessChainLValue(result); - multiTypeStore(node->getType(), load); - } + if (result != spv::NoResult) + builder.createStore(accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()), result); } if (node->getFalseBlock() != nullptr) { ifBuilder.makeBeginElse(); // emit the "else" statement node->getFalseBlock()->traverse(this); - if (result != spv::NoResult) { - spv::Id load = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()); - - builder.clearAccessChain(); - builder.setAccessChainLValue(result); - multiTypeStore(node->getType(), load); - } + if (result != spv::NoResult) + builder.createStore(accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()), result); } // finish off the control flow @@ -4006,8 +3818,10 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node) { +#ifndef GLSLANG_WEB if (node->getQualifier().isSpirvLiteral()) return; // Translated to a literal value, skip further processing +#endif int nextConst = 0; spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false); @@ -4138,6 +3952,7 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T builder.clearAccessChain(); break; +#ifndef GLSLANG_WEB case glslang::EOpDemote: builder.createNoResultOp(spv::OpDemoteToHelperInvocationEXT); builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation); @@ -4149,6 +3964,7 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T case glslang::EOpIgnoreIntersectionKHR: builder.makeStatementTerminator(spv::OpIgnoreIntersectionKHR, "post-ignoreIntersectionKHR"); break; +#endif default: assert(0); @@ -4190,6 +4006,7 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* else builder.addCapability(spv::CapabilityStorageUniform16); break; +#ifndef GLSLANG_WEB case spv::StorageClassPushConstant: builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3); builder.addCapability(spv::CapabilityStoragePushConstant16); @@ -4199,6 +4016,7 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3); builder.addCapability(spv::CapabilityStorageUniformBufferBlock16); break; +#endif default: if (storageClass == spv::StorageClassWorkgroup && node->getType().getBasicType() == glslang::EbtBlock) { @@ -4257,6 +4075,7 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler) case glslang::EbtInt: return builder.makeIntType(32); case glslang::EbtUint: return builder.makeUintType(32); case glslang::EbtFloat: return builder.makeFloatType(32); +#ifndef GLSLANG_WEB case glslang::EbtFloat16: builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float_fetch); builder.addCapability(spv::CapabilityFloat16ImageAMD); @@ -4269,6 +4088,7 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler) builder.addExtension(spv::E_SPV_EXT_shader_image_int64); builder.addCapability(spv::CapabilityInt64ImageEXT); return builder.makeUintType(64); +#endif default: assert(0); return builder.makeFloatType(32); @@ -4344,6 +4164,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty case glslang::EbtFloat: spvType = builder.makeFloatType(32); break; +#ifndef GLSLANG_WEB case glslang::EbtDouble: spvType = builder.makeFloatType(64); break; @@ -4421,6 +4242,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty } } break; +#endif case glslang::EbtSampler: { const glslang::TSampler& sampler = type.getSampler(); @@ -4462,13 +4284,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty case glslang::EbtString: // no type used for OpString return 0; - - case glslang::EbtHitObjectNV: { - builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder); - builder.addCapability(spv::CapabilityShaderInvocationReorderNV); - spvType = builder.makeHitObjectNVType(); - } - break; +#ifndef GLSLANG_WEB case glslang::EbtSpirvType: { // GL_EXT_spirv_intrinsics const auto& spirvType = type.getSpirvType(); @@ -4476,56 +4292,50 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty std::vector operands; for (const auto& typeParam : spirvType.typeParams) { - if (typeParam.constant != nullptr) { - // Constant expression - if (typeParam.constant->isLiteral()) { - if (typeParam.constant->getBasicType() == glslang::EbtFloat) { - float floatValue = static_cast(typeParam.constant->getConstArray()[0].getDConst()); - unsigned literal; - static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)"); - memcpy(&literal, &floatValue, sizeof(literal)); - operands.push_back({false, literal}); - } else if (typeParam.constant->getBasicType() == glslang::EbtInt) { - unsigned literal = typeParam.constant->getConstArray()[0].getIConst(); - operands.push_back({false, literal}); - } else if (typeParam.constant->getBasicType() == glslang::EbtUint) { - unsigned literal = typeParam.constant->getConstArray()[0].getUConst(); - operands.push_back({false, literal}); - } else if (typeParam.constant->getBasicType() == glslang::EbtBool) { - unsigned literal = typeParam.constant->getConstArray()[0].getBConst(); - operands.push_back({false, literal}); - } else if (typeParam.constant->getBasicType() == glslang::EbtString) { - auto str = typeParam.constant->getConstArray()[0].getSConst()->c_str(); - unsigned literal = 0; - char* literalPtr = reinterpret_cast(&literal); - unsigned charCount = 0; - char ch = 0; - do { - ch = *(str++); - *(literalPtr++) = ch; - ++charCount; - if (charCount == 4) { - operands.push_back({false, literal}); - literalPtr = reinterpret_cast(&literal); - charCount = 0; - } - } while (ch != 0); - - // Partial literal is padded with 0 - if (charCount > 0) { - for (; charCount < 4; ++charCount) - *(literalPtr++) = 0; + // Constant expression + if (typeParam.constant->isLiteral()) { + if (typeParam.constant->getBasicType() == glslang::EbtFloat) { + float floatValue = static_cast(typeParam.constant->getConstArray()[0].getDConst()); + unsigned literal; + static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)"); + memcpy(&literal, &floatValue, sizeof(literal)); + operands.push_back({false, literal}); + } else if (typeParam.constant->getBasicType() == glslang::EbtInt) { + unsigned literal = typeParam.constant->getConstArray()[0].getIConst(); + operands.push_back({false, literal}); + } else if (typeParam.constant->getBasicType() == glslang::EbtUint) { + unsigned literal = typeParam.constant->getConstArray()[0].getUConst(); + operands.push_back({false, literal}); + } else if (typeParam.constant->getBasicType() == glslang::EbtBool) { + unsigned literal = typeParam.constant->getConstArray()[0].getBConst(); + operands.push_back({false, literal}); + } else if (typeParam.constant->getBasicType() == glslang::EbtString) { + auto str = typeParam.constant->getConstArray()[0].getSConst()->c_str(); + unsigned literal = 0; + char* literalPtr = reinterpret_cast(&literal); + unsigned charCount = 0; + char ch = 0; + do { + ch = *(str++); + *(literalPtr++) = ch; + ++charCount; + if (charCount == 4) { operands.