mirror of
				https://github.com/ocornut/imgui.git
				synced 2025-10-26 12:27:30 +00:00 
			
		
		
		
	Merge branch 'master' into docking + incl add wd->Pipeline in ImGui_ImplVulkan_RenderDrawData platform code (#3455, #3459)
This commit is contained in:
		| @@ -109,14 +109,21 @@ Other Changes: | ||||
| - Window: Fixed using non-zero pivot in SetNextWindowPos() when the window is collapsed. (#3433) | ||||
| - Nav: Fixed navigation resuming on first visible item when using gamepad. [@rokups] | ||||
| - Nav: Fixed using Alt to toggle the Menu layer when inside a Modal window. (#787) | ||||
| - Scrolling: Fixed SetScrollHere functions edge snapping when called during a frame where ContentSize | ||||
|   is changing (issue introduced in 1.78). (#3452). | ||||
| - InputText: Added selection helpers in ImGuiInputTextCallbackData(). | ||||
| - InputText: Added ImGuiInputTextFlags_CallbackEdit to modify internally owned buffer after an edit. | ||||
|   (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the | ||||
|   underlying buffer while focus is active). | ||||
| - InputText: Fixed using ImGuiInputTextFlags_Password with InputTextMultiline(). (#3427, #3428) | ||||
|   It is a rather unusual or useless combination of features but no reason it shouldn't work! | ||||
| - InputText: Fixed minor scrolling glitch when erasing trailing lines in InputTextMultiline(). | ||||
| - InputText: Fixed cursor being partially covered after using Ctrl+End key. | ||||
| - InputText: Fixed callback's helper DeleteChars() function when cursor is inside the deleted block. (#3454). | ||||
| - DragFloat, DragScalar: Fixed ImGuiSliderFlags_ClampOnInput not being honored in the special case | ||||
|   where v_min == v_max. (#3361) | ||||
| - SliderInt, SliderScalar: Fixed reaching of maximum value with inverted integer min/max ranges, both | ||||
|   with signed and unsigned types. Added reverse Sliders to Demo. (#3432, #3449) [@rokups] | ||||
| - BeginMenuBar: Fixed minor bug where CursorPosMax gets pushed to CursorPos prior to calling BeginMenuBar(), | ||||
|   so e.g. calling the function at the end of a window would often add +ItemSpacing.y to scrolling range. | ||||
| - TreeNode, CollapsingHeader: Made clicking on arrow toggle toggle the open state on the Mouse Down event | ||||
| @@ -128,7 +135,11 @@ Other Changes: | ||||
|   tabs reordered in the tab list popup. [@Xipiryon] | ||||
| - Metrics: Various tweaks, listing windows front-to-back, greying inactive items when possible. | ||||
| - Demo: Add simple InputText() callbacks demo (aside from the more elaborate ones in 'Examples->Console'). | ||||
| - Backends: Vulkan: Some internal refactor aimed at allowing multi-viewport feature to create their | ||||
|   own render pass. (#3455, #3459) [@FunMiles] | ||||
| - Examples: Vulkan: Reworked buffer resize handling, fix for Linux/X11. (#3390, #2626) [@RoryO] | ||||
| - Examples: Vulkan: Switch validation layer to use "VK_LAYER_KHRONOS_validation" instead of | ||||
|   "VK_LAYER_LUNARG_standard_validation" which is deprecated (#3459) [@FunMiles] | ||||
|  | ||||
|  | ||||
| ----------------------------------------------------------------------- | ||||
|   | ||||
| @@ -28,9 +28,11 @@ set(IMGUI_DIR ../../) | ||||
| include_directories(${IMGUI_DIR} ..) | ||||
|  | ||||
| # Libraries | ||||
| find_library(VULKAN_LIBRARY | ||||
|   NAMES vulkan vulkan-1) | ||||
| set(LIBRARIES "glfw;${VULKAN_LIBRARY}") | ||||
| find_package(Vulkan REQUIRED) | ||||
| #find_library(VULKAN_LIBRARY | ||||
|   #NAMES vulkan vulkan-1) | ||||
| #set(LIBRARIES "glfw;${VULKAN_LIBRARY}") | ||||
| set(LIBRARIES "glfw;Vulkan::Vulkan") | ||||
|  | ||||
| # Use vulkan headers from glfw: | ||||
| include_directories(${GLFW_DIR}/deps) | ||||
|   | ||||
| @@ -72,10 +72,9 @@ static void SetupVulkan(const char** extensions, uint32_t extensions_count) | ||||
|         create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; | ||||
|         create_info.enabledExtensionCount = extensions_count; | ||||
|         create_info.ppEnabledExtensionNames = extensions; | ||||
|  | ||||
| #ifdef IMGUI_VULKAN_DEBUG_REPORT | ||||
|         // Enabling multiple validation layers grouped as LunarG standard validation | ||||
|         const char* layers[] = { "VK_LAYER_LUNARG_standard_validation" }; | ||||
|         // Enabling validation layers | ||||
|         const char* layers[] = { "VK_LAYER_KHRONOS_validation" }; | ||||
|         create_info.enabledLayerCount = 1; | ||||
|         create_info.ppEnabledLayerNames = layers; | ||||
|  | ||||
|   | ||||
| @@ -99,6 +99,8 @@ int main(int, char**) | ||||
|             ImGui_ImplSDL2_ProcessEvent(&event); | ||||
|             if (event.type == SDL_QUIT) | ||||
|                 done = true; | ||||
|             if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) | ||||
|                 done = true; | ||||
|         } | ||||
|  | ||||
|         // Start the Dear ImGui frame | ||||
|   | ||||
| @@ -64,10 +64,9 @@ static void SetupVulkan(const char** extensions, uint32_t extensions_count) | ||||
|         create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; | ||||
|         create_info.enabledExtensionCount = extensions_count; | ||||
|         create_info.ppEnabledExtensionNames = extensions; | ||||
|  | ||||
| #ifdef IMGUI_VULKAN_DEBUG_REPORT | ||||
|         // Enabling multiple validation layers grouped as LunarG standard validation | ||||
|         const char* layers[] = { "VK_LAYER_LUNARG_standard_validation" }; | ||||
|         // Enabling validation layers | ||||
|         const char* layers[] = { "VK_LAYER_KHRONOS_validation" }; | ||||
|         create_info.enabledLayerCount = 1; | ||||
|         create_info.ppEnabledLayerNames = layers; | ||||
|  | ||||
| @@ -467,6 +466,8 @@ int main(int, char**) | ||||
|             ImGui_ImplSDL2_ProcessEvent(&event); | ||||
|             if (event.type == SDL_QUIT) | ||||
|                 done = true; | ||||
|             if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) | ||||
|                 done = true; | ||||
|         } | ||||
|  | ||||
|         // Resize swap chain? | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
|  | ||||
| // CHANGELOG | ||||
| // (minor and older changes stripped away, please see git history for details) | ||||
| //  2020-09-07: Vulkan: Added VkPipeline parameter to ImGui_ImplVulkan_RenderDrawData (default to one passed to ImGui_ImplVulkan_Init). | ||||
| //  2020-05-04: Vulkan: Fixed crash if initial frame has no vertices. | ||||
| //  2020-04-26: Vulkan: Fixed edge case where render callbacks wouldn't be called if the ImDrawData didn't have vertices. | ||||
| //  2019-08-01: Vulkan: Added support for specifying multisample count. Set ImGui_ImplVulkan_InitInfo::MSAASamples to one of the VkSampleCountFlagBits values to use, default is non-multisampled as before. | ||||
| @@ -93,6 +94,8 @@ static VkDescriptorSetLayout    g_DescriptorSetLayout = VK_NULL_HANDLE; | ||||
| static VkPipelineLayout         g_PipelineLayout = VK_NULL_HANDLE; | ||||
| static VkDescriptorSet          g_DescriptorSet = VK_NULL_HANDLE; | ||||
| static VkPipeline               g_Pipeline = VK_NULL_HANDLE; | ||||
| static VkShaderModule           g_ShaderModuleVert; | ||||
| static VkShaderModule           g_ShaderModuleFrag; | ||||
|  | ||||
| // Font data | ||||
| static VkSampler                g_FontSampler = VK_NULL_HANDLE; | ||||
| @@ -281,11 +284,11 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory | ||||
|     p_buffer_size = new_size; | ||||
| } | ||||
|  | ||||
| static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkCommandBuffer command_buffer, ImGui_ImplVulkanH_FrameRenderBuffers* rb, int fb_width, int fb_height) | ||||
| static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline pipeline, VkCommandBuffer command_buffer, ImGui_ImplVulkanH_FrameRenderBuffers* rb, int fb_width, int fb_height) | ||||
| { | ||||
|     // Bind pipeline and descriptor sets: | ||||
|     { | ||||
|         vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_Pipeline); | ||||
|         vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||||
|         VkDescriptorSet desc_set[1] = { g_DescriptorSet }; | ||||
|         vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL); | ||||
|     } | ||||
| @@ -327,7 +330,7 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkCommandBu | ||||
|  | ||||
| // Render function | ||||
| // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) | ||||
| void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer) | ||||
| void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline) | ||||
| { | ||||
|     // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) | ||||
|     int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); | ||||
| @@ -336,6 +339,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm | ||||
|         return; | ||||
|  | ||||
|     ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo; | ||||
|     if (pipeline == VK_NULL_HANDLE) | ||||
|         pipeline = g_Pipeline; | ||||
|  | ||||
|     // Allocate array to store enough vertex/index buffers. Each unique viewport gets its own storage. | ||||
|     ImGuiViewportDataVulkan* viewport_renderer_data = (ImGuiViewportDataVulkan*)draw_data->OwnerViewport->RendererUserData; | ||||
| @@ -391,7 +396,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm | ||||
|     } | ||||
|  | ||||
|     // Setup desired Vulkan state | ||||
|     ImGui_ImplVulkan_SetupRenderState(draw_data, command_buffer, rb, fb_width, fb_height); | ||||
|     ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); | ||||
|  | ||||
|     // Will project scissor/clipping rectangles into framebuffer space | ||||
|     ImVec2 clip_off = draw_data->DisplayPos;         // (0,0) unless using multi-viewports | ||||
| @@ -412,7 +417,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm | ||||
|                 // User callback, registered via ImDrawList::AddCallback() | ||||
|                 // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) | ||||
|                 if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) | ||||
|                     ImGui_ImplVulkan_SetupRenderState(draw_data, command_buffer, rb, fb_width, fb_height); | ||||
|                     ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); | ||||
|                 else | ||||
|                     pcmd->UserCallback(cmd_list, pcmd); | ||||
|             } | ||||
| @@ -603,6 +608,195 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator) | ||||
| { | ||||
|     // Create the shader modules | ||||
|     if (g_ShaderModuleVert == NULL) | ||||
|     { | ||||
|         VkShaderModuleCreateInfo vert_info = {}; | ||||
|         vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; | ||||
|         vert_info.codeSize = sizeof(__glsl_shader_vert_spv); | ||||
|         vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv; | ||||
|         VkResult err = vkCreateShaderModule(device, &vert_info, allocator, &g_ShaderModuleVert); | ||||
|         check_vk_result(err); | ||||
|     } | ||||
|     if (g_ShaderModuleFrag == NULL) | ||||
|     { | ||||
|         VkShaderModuleCreateInfo frag_info = {}; | ||||
|         frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; | ||||
|         frag_info.codeSize = sizeof(__glsl_shader_frag_spv); | ||||
|         frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv; | ||||
|         VkResult err = vkCreateShaderModule(device, &frag_info, allocator, &g_ShaderModuleFrag); | ||||
|         check_vk_result(err); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void ImGui_ImplVulkan_CreateFontSampler(VkDevice device, const VkAllocationCallbacks* allocator) | ||||
| { | ||||
|     if (g_FontSampler) | ||||
|         return; | ||||
|  | ||||
|     VkSamplerCreateInfo info = {}; | ||||
|     info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; | ||||
|     info.magFilter = VK_FILTER_LINEAR; | ||||
|     info.minFilter = VK_FILTER_LINEAR; | ||||
|     info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; | ||||
|     info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; | ||||
|     info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; | ||||
|     info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; | ||||
|     info.minLod = -1000; | ||||
|     info.maxLod = 1000; | ||||
|     info.maxAnisotropy = 1.0f; | ||||
|     VkResult err = vkCreateSampler(device, &info, allocator, &g_FontSampler); | ||||
|     check_vk_result(err); | ||||
| } | ||||
|  | ||||
| static void ImGui_ImplVulkan_CreateDescriptorSetLayout(VkDevice device, const VkAllocationCallbacks* allocator) | ||||
| { | ||||
|     if (g_DescriptorSetLayout) | ||||
|         return; | ||||
|  | ||||
|     ImGui_ImplVulkan_CreateFontSampler(device, allocator); | ||||
|     VkSampler sampler[1] = { g_FontSampler }; | ||||
|     VkDescriptorSetLayoutBinding binding[1] = {}; | ||||
|     binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; | ||||
|     binding[0].descriptorCount = 1; | ||||
|     binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; | ||||
|     binding[0].pImmutableSamplers = sampler; | ||||
|     VkDescriptorSetLayoutCreateInfo info = {}; | ||||
|     info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; | ||||
|     info.bindingCount = 1; | ||||
|     info.pBindings = binding; | ||||
|     VkResult err = vkCreateDescriptorSetLayout(device, &info, allocator, &g_DescriptorSetLayout); | ||||
|     check_vk_result(err); | ||||
| } | ||||
|  | ||||
| static void ImGui_ImplVulkan_CreatePipelineLayout(VkDevice device, const VkAllocationCallbacks* allocator) | ||||
| { | ||||
|     if (g_PipelineLayout) | ||||
|         return; | ||||
|  | ||||
|     // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix | ||||
|     ImGui_ImplVulkan_CreateDescriptorSetLayout(device, allocator); | ||||
|     VkPushConstantRange push_constants[1] = {}; | ||||
|     push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; | ||||
|     push_constants[0].offset = sizeof(float) * 0; | ||||
|     push_constants[0].size = sizeof(float) * 4; | ||||
|     VkDescriptorSetLayout set_layout[1] = { g_DescriptorSetLayout }; | ||||
|     VkPipelineLayoutCreateInfo layout_info = {}; | ||||
|     layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; | ||||
|     layout_info.setLayoutCount = 1; | ||||
|     layout_info.pSetLayouts = set_layout; | ||||
|     layout_info.pushConstantRangeCount = 1; | ||||
|     layout_info.pPushConstantRanges = push_constants; | ||||
|     VkResult  err = vkCreatePipelineLayout(device, &layout_info, allocator, &g_PipelineLayout); | ||||
|     check_vk_result(err); | ||||
| } | ||||
|  | ||||
| static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, VkPipeline *pipeline) | ||||
| { | ||||
|     ImGui_ImplVulkan_CreateShaderModules(device, allocator); | ||||
|  | ||||
|     VkPipelineShaderStageCreateInfo stage[2] = {}; | ||||
|     stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; | ||||
|     stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT; | ||||
|     stage[0].module = g_ShaderModuleVert; | ||||
|     stage[0].pName = "main"; | ||||
|     stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; | ||||
|     stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; | ||||
|     stage[1].module = g_ShaderModuleFrag; | ||||
|     stage[1].pName = "main"; | ||||
|  | ||||
|     VkVertexInputBindingDescription binding_desc[1] = {}; | ||||
|     binding_desc[0].stride = sizeof(ImDrawVert); | ||||
|     binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; | ||||
|  | ||||
|     VkVertexInputAttributeDescription attribute_desc[3] = {}; | ||||
|     attribute_desc[0].location = 0; | ||||
|     attribute_desc[0].binding = binding_desc[0].binding; | ||||
|     attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT; | ||||
|     attribute_desc[0].offset = IM_OFFSETOF(ImDrawVert, pos); | ||||
|     attribute_desc[1].location = 1; | ||||
|     attribute_desc[1].binding = binding_desc[0].binding; | ||||
|     attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT; | ||||
|     attribute_desc[1].offset = IM_OFFSETOF(ImDrawVert, uv); | ||||
|     attribute_desc[2].location = 2; | ||||
|     attribute_desc[2].binding = binding_desc[0].binding; | ||||
|     attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM; | ||||
|     attribute_desc[2].offset = IM_OFFSETOF(ImDrawVert, col); | ||||
|  | ||||
|     VkPipelineVertexInputStateCreateInfo vertex_info = {}; | ||||
|     vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; | ||||
|     vertex_info.vertexBindingDescriptionCount = 1; | ||||
|     vertex_info.pVertexBindingDescriptions = binding_desc; | ||||
|     vertex_info.vertexAttributeDescriptionCount = 3; | ||||
|     vertex_info.pVertexAttributeDescriptions = attribute_desc; | ||||
|  | ||||
|     VkPipelineInputAssemblyStateCreateInfo ia_info = {}; | ||||
|     ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; | ||||
|     ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; | ||||
|  | ||||
|     VkPipelineViewportStateCreateInfo viewport_info = {}; | ||||
|     viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; | ||||
|     viewport_info.viewportCount = 1; | ||||
|     viewport_info.scissorCount = 1; | ||||
|  | ||||
|     VkPipelineRasterizationStateCreateInfo raster_info = {}; | ||||
|     raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; | ||||
|     raster_info.polygonMode = VK_POLYGON_MODE_FILL; | ||||
|     raster_info.cullMode = VK_CULL_MODE_NONE; | ||||
|     raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; | ||||
|     raster_info.lineWidth = 1.0f; | ||||
|  | ||||
|     VkPipelineMultisampleStateCreateInfo ms_info = {}; | ||||
|     ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; | ||||
|     ms_info.rasterizationSamples = (MSAASamples != 0) ? MSAASamples : VK_SAMPLE_COUNT_1_BIT; | ||||
|  | ||||
|     VkPipelineColorBlendAttachmentState color_attachment[1] = {}; | ||||
|     color_attachment[0].blendEnable = VK_TRUE; | ||||
|     color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; | ||||
|     color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; | ||||
|     color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD; | ||||
|     color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; | ||||
|     color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; | ||||
|     color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD; | ||||
|     color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; | ||||
|  | ||||
|     VkPipelineDepthStencilStateCreateInfo depth_info = {}; | ||||
|     depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; | ||||
|  | ||||
|     VkPipelineColorBlendStateCreateInfo blend_info = {}; | ||||
|     blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; | ||||
|     blend_info.attachmentCount = 1; | ||||
|     blend_info.pAttachments = color_attachment; | ||||
|  | ||||
|     VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; | ||||
|     VkPipelineDynamicStateCreateInfo dynamic_state = {}; | ||||
|     dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; | ||||
|     dynamic_state.dynamicStateCount = (uint32_t)IM_ARRAYSIZE(dynamic_states); | ||||
|     dynamic_state.pDynamicStates = dynamic_states; | ||||
|  | ||||
|     ImGui_ImplVulkan_CreatePipelineLayout(device, allocator); | ||||
|  | ||||
|     VkGraphicsPipelineCreateInfo info = {}; | ||||
|     info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; | ||||
|     info.flags = g_PipelineCreateFlags; | ||||
|     info.stageCount = 2; | ||||
|     info.pStages = stage; | ||||
|     info.pVertexInputState = &vertex_info; | ||||
|     info.pInputAssemblyState = &ia_info; | ||||
|     info.pViewportState = &viewport_info; | ||||
|     info.pRasterizationState = &raster_info; | ||||
|     info.pMultisampleState = &ms_info; | ||||
|     info.pDepthStencilState = &depth_info; | ||||
|     info.pColorBlendState = &blend_info; | ||||
|     info.pDynamicState = &dynamic_state; | ||||
|     info.layout = g_PipelineLayout; | ||||
|     info.renderPass = renderPass; | ||||
|     VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, pipeline); | ||||
|     check_vk_result(err); | ||||
| } | ||||
|  | ||||
| bool ImGui_ImplVulkan_CreateDeviceObjects() | ||||
| { | ||||
|     ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo; | ||||
| @@ -688,105 +882,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() | ||||
|         check_vk_result(err); | ||||
|     } | ||||
|  | ||||
|     VkPipelineShaderStageCreateInfo stage[2] = {}; | ||||
|     stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; | ||||
|     stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT; | ||||
|     stage[0].module = vert_module; | ||||
|     stage[0].pName = "main"; | ||||
|     stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; | ||||
|     stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; | ||||
|     stage[1].module = frag_module; | ||||
|     stage[1].pName = "main"; | ||||
|  | ||||
|     VkVertexInputBindingDescription binding_desc[1] = {}; | ||||
|     binding_desc[0].stride = sizeof(ImDrawVert); | ||||
|     binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; | ||||
|  | ||||
|     VkVertexInputAttributeDescription attribute_desc[3] = {}; | ||||
|     attribute_desc[0].location = 0; | ||||
|     attribute_desc[0].binding = binding_desc[0].binding; | ||||
|     attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT; | ||||
|     attribute_desc[0].offset = IM_OFFSETOF(ImDrawVert, pos); | ||||
|     attribute_desc[1].location = 1; | ||||
|     attribute_desc[1].binding = binding_desc[0].binding; | ||||
|     attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT; | ||||
|     attribute_desc[1].offset = IM_OFFSETOF(ImDrawVert, uv); | ||||
|     attribute_desc[2].location = 2; | ||||
|     attribute_desc[2].binding = binding_desc[0].binding; | ||||
|     attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM; | ||||
|     attribute_desc[2].offset = IM_OFFSETOF(ImDrawVert, col); | ||||
|  | ||||
|     VkPipelineVertexInputStateCreateInfo vertex_info = {}; | ||||
|     vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; | ||||
|     vertex_info.vertexBindingDescriptionCount = 1; | ||||
|     vertex_info.pVertexBindingDescriptions = binding_desc; | ||||
|     vertex_info.vertexAttributeDescriptionCount = 3; | ||||
|     vertex_info.pVertexAttributeDescriptions = attribute_desc; | ||||
|  | ||||
|     VkPipelineInputAssemblyStateCreateInfo ia_info = {}; | ||||
|     ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; | ||||
|     ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; | ||||
|  | ||||
|     VkPipelineViewportStateCreateInfo viewport_info = {}; | ||||
|     viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; | ||||
|     viewport_info.viewportCount = 1; | ||||
|     viewport_info.scissorCount = 1; | ||||
|  | ||||
|     VkPipelineRasterizationStateCreateInfo raster_info = {}; | ||||
|     raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; | ||||
|     raster_info.polygonMode = VK_POLYGON_MODE_FILL; | ||||
|     raster_info.cullMode = VK_CULL_MODE_NONE; | ||||
|     raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; | ||||
|     raster_info.lineWidth = 1.0f; | ||||
|  | ||||
|     VkPipelineMultisampleStateCreateInfo ms_info = {}; | ||||
|     ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; | ||||
|     if (v->MSAASamples != 0) | ||||
|         ms_info.rasterizationSamples = v->MSAASamples; | ||||
|     else | ||||
|         ms_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; | ||||
|  | ||||
|     VkPipelineColorBlendAttachmentState color_attachment[1] = {}; | ||||
|     color_attachment[0].blendEnable = VK_TRUE; | ||||
|     color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; | ||||
|     color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; | ||||
|     color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD; | ||||
|     color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; | ||||
|     color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; | ||||
|     color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD; | ||||
|     color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; | ||||
|  | ||||
|     VkPipelineDepthStencilStateCreateInfo depth_info = {}; | ||||
|     depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; | ||||
|  | ||||
|     VkPipelineColorBlendStateCreateInfo blend_info = {}; | ||||
|     blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; | ||||
|     blend_info.attachmentCount = 1; | ||||
|     blend_info.pAttachments = color_attachment; | ||||
|  | ||||
|     VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; | ||||
|     VkPipelineDynamicStateCreateInfo dynamic_state = {}; | ||||
|     dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; | ||||
|     dynamic_state.dynamicStateCount = (uint32_t)IM_ARRAYSIZE(dynamic_states); | ||||
|     dynamic_state.pDynamicStates = dynamic_states; | ||||
|  | ||||
|     VkGraphicsPipelineCreateInfo info = {}; | ||||
|     info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; | ||||
|     info.flags = g_PipelineCreateFlags; | ||||
|     info.stageCount = 2; | ||||
|     info.pStages = stage; | ||||
|     info.pVertexInputState = &vertex_info; | ||||
|     info.pInputAssemblyState = &ia_info; | ||||
|     info.pViewportState = &viewport_info; | ||||
|     info.pRasterizationState = &raster_info; | ||||
|     info.pMultisampleState = &ms_info; | ||||
|     info.pDepthStencilState = &depth_info; | ||||
|     info.pColorBlendState = &blend_info; | ||||
|     info.pDynamicState = &dynamic_state; | ||||
|     info.layout = g_PipelineLayout; | ||||
|     info.renderPass = g_RenderPass; | ||||
|     err = vkCreateGraphicsPipelines(v->Device, v->PipelineCache, 1, &info, v->Allocator, &g_Pipeline); | ||||
|     check_vk_result(err); | ||||
|     ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, g_RenderPass, v->MSAASamples, &g_Pipeline); | ||||
|  | ||||
|     vkDestroyShaderModule(v->Device, vert_module, v->Allocator); | ||||
|     vkDestroyShaderModule(v->Device, frag_module, v->Allocator); | ||||
| @@ -1054,6 +1150,8 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V | ||||
|     wd->ImageCount = 0; | ||||
|     if (wd->RenderPass) | ||||
|         vkDestroyRenderPass(device, wd->RenderPass, allocator); | ||||
|     if (wd->Pipeline) | ||||
|         vkDestroyPipeline(device, wd->Pipeline, allocator); | ||||
|  | ||||
|     // If min image count was not specified, request different count of images dependent on selected present mode | ||||
|     if (min_image_count == 0) | ||||
| @@ -1149,6 +1247,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V | ||||
|         info.pDependencies = &dependency; | ||||
|         err = vkCreateRenderPass(device, &info, allocator, &wd->RenderPass); | ||||
|         check_vk_result(err); | ||||
|         ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline); | ||||
|     } | ||||
|  | ||||
|     // Create The Image Views | ||||
| @@ -1385,7 +1484,7 @@ static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     ImGui_ImplVulkan_RenderDrawData(viewport->DrawData, fd->CommandBuffer); | ||||
|     ImGui_ImplVulkan_RenderDrawData(viewport->DrawData, fd->CommandBuffer, wd->Pipeline); | ||||
|  | ||||
|     { | ||||
|         vkCmdEndRenderPass(fd->CommandBuffer); | ||||
|   | ||||
| @@ -47,7 +47,7 @@ struct ImGui_ImplVulkan_InitInfo | ||||
| IMGUI_IMPL_API bool     ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass); | ||||
| IMGUI_IMPL_API void     ImGui_ImplVulkan_Shutdown(); | ||||
| IMGUI_IMPL_API void     ImGui_ImplVulkan_NewFrame(); | ||||
| IMGUI_IMPL_API void     ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer); | ||||
| IMGUI_IMPL_API void     ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE); | ||||
| IMGUI_IMPL_API bool     ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer); | ||||
| IMGUI_IMPL_API void     ImGui_ImplVulkan_DestroyFontUploadObjects(); | ||||
| IMGUI_IMPL_API void     ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) | ||||
| @@ -109,6 +109,7 @@ struct ImGui_ImplVulkanH_Window | ||||
|     VkSurfaceFormatKHR  SurfaceFormat; | ||||
|     VkPresentModeKHR    PresentMode; | ||||
|     VkRenderPass        RenderPass; | ||||
|     VkPipeline          Pipeline;               // The window pipeline uses a different VkRenderPass than the user's | ||||
|     bool                ClearEnable; | ||||
|     VkClearValue        ClearValue; | ||||
|     uint32_t            FrameIndex;             // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount) | ||||
|   | ||||
							
								
								
									
										118
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -8083,21 +8083,42 @@ void ImGui::EndGroup() | ||||
| // [SECTION] SCROLLING | ||||
| //----------------------------------------------------------------------------- | ||||
|  | ||||
| // Helper to snap on edges when aiming at an item very close to the edge, | ||||
| // So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling. | ||||
| // When we refactor the scrolling API this may be configurable with a flag? | ||||
| // Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default. | ||||
| static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio) | ||||
| { | ||||
|     if (target <= snap_min + snap_threshold) | ||||
|         return ImLerp(snap_min, target, center_ratio); | ||||
|     if (target >= snap_max - snap_threshold) | ||||
|         return ImLerp(target, snap_max, center_ratio); | ||||
|     return target; | ||||
| } | ||||
|  | ||||
| static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) | ||||
| { | ||||
|     ImVec2 scroll = window->Scroll; | ||||
|     if (window->ScrollTarget.x < FLT_MAX) | ||||
|     { | ||||
|         float cr_x = window->ScrollTargetCenterRatio.x; | ||||
|         float target_x = window->ScrollTarget.x; | ||||
|         scroll.x = target_x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x); | ||||
|         float center_x_ratio = window->ScrollTargetCenterRatio.x; | ||||
|         float scroll_target_x = window->ScrollTarget.x; | ||||
|         float snap_x_min = 0.0f; | ||||
|         float snap_x_max = window->ScrollMax.x + window->Size.x; | ||||
|         if (window->ScrollTargetEdgeSnapDist.x > 0.0f) | ||||
|             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 - window->ScrollbarSizes.x); | ||||
|     } | ||||
|     if (window->ScrollTarget.y < FLT_MAX) | ||||
|     { | ||||
|         float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); | ||||
|         float cr_y = window->ScrollTargetCenterRatio.y; | ||||
|         float target_y = window->ScrollTarget.y; | ||||
|         scroll.y = target_y - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height); | ||||
|         float center_y_ratio = window->ScrollTargetCenterRatio.y; | ||||
|         float scroll_target_y = window->ScrollTarget.y; | ||||
|         float snap_y_min = 0.0f; | ||||
|         float snap_y_max = window->ScrollMax.y + window->Size.y - decoration_up_height; | ||||
|         if (window->ScrollTargetEdgeSnapDist.y > 0.0f) | ||||
|             scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio); | ||||
|         scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height); | ||||
|     } | ||||
|     scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f)); | ||||
|     scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f)); | ||||
| @@ -8163,47 +8184,57 @@ float ImGui::GetScrollMaxY() | ||||
|     return window->ScrollMax.y; | ||||
| } | ||||
|  | ||||
| void ImGui::SetScrollX(float scroll_x) | ||||
| void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     window->ScrollTarget.x = scroll_x; | ||||
|     window->ScrollTargetCenterRatio.x = 0.0f; | ||||
|     window->ScrollTargetEdgeSnapDist.x = 0.0f; | ||||
| } | ||||
|  | ||||
| void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y) | ||||
| { | ||||
|     window->ScrollTarget.y = scroll_y; | ||||
|     window->ScrollTargetCenterRatio.y = 0.0f; | ||||
|     window->ScrollTargetEdgeSnapDist.y = 0.0f; | ||||
| } | ||||
|  | ||||
| void ImGui::SetScrollX(float scroll_x) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     SetScrollX(g.CurrentWindow, scroll_x); | ||||
| } | ||||
|  | ||||
| void ImGui::SetScrollY(float scroll_y) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     window->ScrollTarget.y = scroll_y; | ||||
|     window->ScrollTargetCenterRatio.y = 0.0f; | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     SetScrollY(g.CurrentWindow, scroll_y); | ||||
| } | ||||
|  | ||||
| void ImGui::SetScrollX(ImGuiWindow* window, float new_scroll_x) | ||||
| { | ||||
|     window->ScrollTarget.x = new_scroll_x; | ||||
|     window->ScrollTargetCenterRatio.x = 0.0f; | ||||
| } | ||||
|  | ||||
| void ImGui::SetScrollY(ImGuiWindow* window, float new_scroll_y) | ||||
| { | ||||
|     window->ScrollTarget.y = new_scroll_y; | ||||
|     window->ScrollTargetCenterRatio.y = 0.0f; | ||||
| } | ||||
|  | ||||
| // Note that a local position will vary depending on initial scroll value | ||||
| // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size | ||||
| // Note that a local position will vary depending on initial scroll value, | ||||
| // This is a little bit confusing so bear with us: | ||||
| //  - local_pos = (absolution_pos - window->Pos) | ||||
| //  - So local_x/local_y are 0.0f for a position at the upper-left corner of a window, | ||||
| //    and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area. | ||||
| //  - They mostly exists because of legacy API. | ||||
| // Following the rules above, when trying to work with scrolling code, consider that: | ||||
| //  - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect! | ||||
| //  - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense | ||||
| // We store a target position so centering and clamping can occur on the next frame when we are guaranteed to have a known window size | ||||
| 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->Scroll.x); | ||||
|     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; | ||||
| } | ||||
|  | ||||
| void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio) | ||||
| { | ||||
|     IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); | ||||
|     local_y -= window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect | ||||
|     window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); | ||||
|     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; | ||||
| } | ||||
|  | ||||
| void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio) | ||||
| @@ -8218,34 +8249,17 @@ void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) | ||||
|     SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio); | ||||
| } | ||||
|  | ||||
| // Tweak: snap on edges when aiming at an item very close to the edge, | ||||
| // So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling. | ||||
| // When we refactor the scrolling API this may be configurable with a flag? | ||||
| // Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default. | ||||
| static float CalcScrollSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio) | ||||
| { | ||||
|     if (target <= snap_min + snap_threshold) | ||||
|         return ImLerp(snap_min, target, center_ratio); | ||||
|     if (target >= snap_max - snap_threshold) | ||||
|         return ImLerp(target, snap_max, center_ratio); | ||||
|     return target; | ||||
| } | ||||
|  | ||||
| // center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item. | ||||
| void ImGui::SetScrollHereX(float center_x_ratio) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* window = g.CurrentWindow; | ||||
|     float spacing_x = g.Style.ItemSpacing.x; | ||||
|     float target_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio); | ||||
|     float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio); | ||||
|     SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos | ||||
|  | ||||
|     // Tweak: snap on edges when aiming at an item very close to the edge | ||||
|     const float snap_x_threshold = ImMax(0.0f, window->WindowPadding.x - spacing_x); | ||||
|     const float snap_x_min = window->DC.CursorStartPos.x - window->WindowPadding.x; | ||||
|     const float snap_x_max = window->DC.CursorStartPos.x + window->ContentSize.x + window->WindowPadding.x; | ||||
|     target_x = CalcScrollSnap(target_x, snap_x_min, snap_x_max, snap_x_threshold, center_x_ratio); | ||||
|  | ||||
|     SetScrollFromPosX(window, target_x - window->Pos.x, center_x_ratio); | ||||
|     window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x); | ||||
| } | ||||
|  | ||||
| // center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. | ||||
| @@ -8254,15 +8268,11 @@ void ImGui::SetScrollHereY(float center_y_ratio) | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* window = g.CurrentWindow; | ||||
|     float spacing_y = g.Style.ItemSpacing.y; | ||||
|     float target_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio); | ||||
|     float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio); | ||||
|     SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos | ||||
|  | ||||
|     // Tweak: snap on edges when aiming at an item very close to the edge | ||||
|     const float snap_y_threshold = ImMax(0.0f, window->WindowPadding.y - spacing_y); | ||||
|     const float snap_y_min = window->DC.CursorStartPos.y - window->WindowPadding.y; | ||||
|     const float snap_y_max = window->DC.CursorStartPos.y + window->ContentSize.y + window->WindowPadding.y; | ||||
|     target_y = CalcScrollSnap(target_y, snap_y_min, snap_y_max, snap_y_threshold, center_y_ratio); | ||||
|  | ||||
|     SetScrollFromPosY(window, target_y - window->Pos.y, center_y_ratio); | ||||
|     window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y); | ||||
| } | ||||
|  | ||||
| //----------------------------------------------------------------------------- | ||||
|   | ||||
							
								
								
									
										4
									
								
								imgui.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								imgui.h
									
									
									
									
									
								
							| @@ -1470,7 +1470,7 @@ struct ImVector | ||||
|     inline bool         empty() const                       { return Size == 0; } | ||||
|     inline int          size() const                        { return Size; } | ||||
|     inline int          size_in_bytes() const               { return Size * (int)sizeof(T); } | ||||
|     inline int          max_size() const                    { return (~(unsigned int)0) / (int)sizeof(T); } | ||||
|     inline int          max_size() const                    { return 0x7FFFFFFF / (int)sizeof(T); } | ||||
|     inline int          capacity() const                    { return Capacity; } | ||||
|     inline T&           operator[](int i)                   { IM_ASSERT(i < Size); return Data[i]; } | ||||
|     inline const T&     operator[](int i) const             { IM_ASSERT(i < Size); return Data[i]; } | ||||
| @@ -2547,7 +2547,7 @@ struct ImFont | ||||
|     IMGUI_API void              BuildLookupTable(); | ||||
|     IMGUI_API void              ClearOutputData(); | ||||
|     IMGUI_API void              GrowIndex(int new_size); | ||||
|     IMGUI_API void              AddGlyph(ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); | ||||
|     IMGUI_API void              AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); | ||||
|     IMGUI_API void              AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. | ||||
|     IMGUI_API void              SetGlyphVisible(ImWchar c, bool visible); | ||||
|     IMGUI_API void              SetFallbackChar(ImWchar c); | ||||
|   | ||||
| @@ -672,7 +672,7 @@ static void ShowDemoWindowWidgets() | ||||
|                 "Hold SHIFT/ALT for faster/slower edit.\n" | ||||
|                 "Double-click or CTRL+click to input value."); | ||||
|  | ||||
|             ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%"); | ||||
|             ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_ClampOnInput); | ||||
|  | ||||
|             static float f1 = 1.00f, f2 = 0.0067f; | ||||
|             ImGui::DragFloat("drag float", &f1, 0.005f); | ||||
| @@ -1743,6 +1743,14 @@ 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::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"); | ||||
|         ImGui::SliderScalar("slider u32 reverse",   ImGuiDataType_U32,  &u32_v, &u32_fifty, &u32_zero, "%u"); | ||||
|         ImGui::SliderScalar("slider s64 reverse",   ImGuiDataType_S64,  &s64_v, &s64_fifty, &s64_zero, "%I64d"); | ||||
|         ImGui::SliderScalar("slider u64 reverse",   ImGuiDataType_U64,  &u64_v, &u64_fifty, &u64_zero, "%I64u ms"); | ||||
|  | ||||
|         static bool inputs_step = true; | ||||
|         ImGui::Text("Inputs"); | ||||
|         ImGui::Checkbox("Show step buttons", &inputs_step); | ||||
| @@ -4291,9 +4299,9 @@ struct ExampleAppConsole | ||||
|         } | ||||
|  | ||||
|         ImGui::TextWrapped( | ||||
|             "This example implements a console with basic coloring, completion and history. A more elaborate " | ||||
|             "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate " | ||||
|             "implementation may want to store entries along with extra data such as timestamp, emitter, etc."); | ||||
|         ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion."); | ||||
|         ImGui::TextWrapped("Enter 'HELP' for help."); | ||||
|  | ||||
|         // TODO: display items starting from the bottom | ||||
|  | ||||
|   | ||||
| @@ -2892,7 +2892,7 @@ void ImFont::GrowIndex(int new_size) | ||||
| // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. | ||||
| // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). | ||||
| // 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font. | ||||
| void ImFont::AddGlyph(ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) | ||||
| void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) | ||||
| { | ||||
|     if (cfg != NULL) | ||||
|     { | ||||
|   | ||||
| @@ -1774,6 +1774,7 @@ struct IMGUI_API ImGuiWindow | ||||
|     ImVec2                  ScrollMax; | ||||
|     ImVec2                  ScrollTarget;                       // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) | ||||
|     ImVec2                  ScrollTargetCenterRatio;            // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered | ||||
|     ImVec2                  ScrollTargetEdgeSnapDist;           // 0.0f = no snapping, >0.0f snapping threshold | ||||
|     ImVec2                  ScrollbarSizes;                     // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar. | ||||
|     bool                    ScrollbarX, ScrollbarY;             // Are scrollbars visible? | ||||
|     bool                    ViewportOwned; | ||||
| @@ -2043,10 +2044,10 @@ namespace ImGui | ||||
|  | ||||
|     // Scrolling | ||||
|     IMGUI_API void          SetNextWindowScroll(const ImVec2& scroll); // Use -1.0f on one axis to leave as-is | ||||
|     IMGUI_API void          SetScrollX(ImGuiWindow* window, float new_scroll_x); | ||||
|     IMGUI_API void          SetScrollY(ImGuiWindow* window, float new_scroll_y); | ||||
|     IMGUI_API void          SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio = 0.5f); | ||||
|     IMGUI_API void          SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio = 0.5f); | ||||
|     IMGUI_API void          SetScrollX(ImGuiWindow* window, float scroll_x); | ||||
|     IMGUI_API void          SetScrollY(ImGuiWindow* window, float scroll_y); | ||||
|     IMGUI_API void          SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio); | ||||
|     IMGUI_API void          SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio); | ||||
|     IMGUI_API ImVec2        ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect); | ||||
|  | ||||
|     // Basic Accessors | ||||
| @@ -2262,8 +2263,8 @@ namespace ImGui | ||||
|     // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. | ||||
|     // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). | ||||
|     // e.g. " extern template IMGUI_API float RoundScalarWithFormatT<float, float>(const char* format, ImGuiDataType data_type, float v); " | ||||
|     template<typename T, typename FLOAT_T>                      IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); | ||||
|     template<typename T, typename FLOAT_T>                      IMGUI_API T     ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); | ||||
|     template<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); | ||||
|     template<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API T     ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); | ||||
|     template<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API bool  DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiSliderFlags flags); | ||||
|     template<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API bool  SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); | ||||
|     template<typename T, typename SIGNED_T>                     IMGUI_API T     RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); | ||||
|   | ||||
| @@ -2101,9 +2101,9 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const | ||||
|         logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); | ||||
|  | ||||
|         // Convert to parametric space, apply delta, convert back | ||||
|         float v_old_parametric = ScaleRatioFromValueT<TYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|         float v_old_parametric = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|         float v_new_parametric = v_old_parametric + g.DragCurrentAccum; | ||||
|         v_cur = ScaleValueFromRatioT<TYPE, FLOATTYPE>(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|         v_cur = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|         v_old_ref_for_accum_remainder = v_old_parametric; | ||||
|     } | ||||
|     else | ||||
| @@ -2120,7 +2120,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const | ||||
|     if (is_logarithmic) | ||||
|     { | ||||
|         // Convert to parametric space, apply delta, convert back | ||||
|         float v_new_parametric = ScaleRatioFromValueT<TYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|         float v_new_parametric = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|         g.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder); | ||||
|     } | ||||
|     else | ||||
| @@ -2456,7 +2456,7 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data | ||||
| //------------------------------------------------------------------------- | ||||
|  | ||||
| // Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of ScaleValueFromRatioT) | ||||
| template<typename TYPE, typename FLOATTYPE> | ||||
| template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE> | ||||
| float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) | ||||
| { | ||||
|     if (v_min == v_max) | ||||
| @@ -2508,11 +2508,11 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T | ||||
|     } | ||||
|  | ||||
|     // Linear slider | ||||
|     return (float)((FLOATTYPE)(v_clamped - v_min) / (FLOATTYPE)(v_max - v_min)); | ||||
|     return (float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min)); | ||||
| } | ||||
|  | ||||
| // Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT) | ||||
| template<typename TYPE, typename FLOATTYPE> | ||||
| template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE> | ||||
| TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) | ||||
| { | ||||
|     if (v_min == v_max) | ||||
| @@ -2571,15 +2571,19 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // For integer values we want the clicking position to match the grab box so we round above | ||||
|             // - For integer values we want the clicking position to match the grab box so we round above | ||||
|             //   This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. | ||||
|             FLOATTYPE v_new_off_f = (v_max - v_min) * t; | ||||
|             TYPE v_new_off_floor = (TYPE)(v_new_off_f); | ||||
|             TYPE v_new_off_round = (TYPE)(v_new_off_f + (FLOATTYPE)0.5); | ||||
|             if (v_new_off_floor < v_new_off_round) | ||||
|                 result = v_min + v_new_off_round; | ||||
|             // - Not doing a *1.0 multiply at the end of a range as it tends to be lossy. While absolute aiming at a large s64/u64 | ||||
|             //   range is going to be imprecise anyway, with this check we at least make the edge values matches expected limits. | ||||
|             if (t < 1.0) | ||||
|             { | ||||
|                 FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t; | ||||
|                 result = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5))); | ||||
|             } | ||||
|             else | ||||
|                 result = v_min + v_new_off_floor; | ||||
|             { | ||||
|                 result = v_max; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -2679,7 +2683,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ | ||||
|             } | ||||
|             else if (g.SliderCurrentAccumDirty) | ||||
|             { | ||||
|                 clicked_t = ScaleRatioFromValueT<TYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|                 clicked_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|  | ||||
|                 if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits | ||||
|                 { | ||||
| @@ -2693,10 +2697,10 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ | ||||
|                     clicked_t = ImSaturate(clicked_t + delta); | ||||
|  | ||||
|                     // Calculate what our "new" clicked_t will be, and thus how far we actually moved the slider, and subtract this from the accumulator | ||||
|                     TYPE v_new = ScaleValueFromRatioT<TYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|                     TYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|                     if (!(flags & ImGuiSliderFlags_NoRoundToFormat)) | ||||
|                         v_new = RoundScalarWithFormatT<TYPE, SIGNEDTYPE>(format, data_type, v_new); | ||||
|                     float new_clicked_t = ScaleRatioFromValueT<TYPE, FLOATTYPE>(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|                     float new_clicked_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|  | ||||
|                     if (delta > 0) | ||||
|                         g.SliderCurrentAccum -= ImMin(new_clicked_t - old_clicked_t, delta); | ||||
| @@ -2710,7 +2714,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ | ||||
|  | ||||
|         if (set_new_value) | ||||
|         { | ||||
|             TYPE v_new = ScaleValueFromRatioT<TYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|             TYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|  | ||||
|             // Round to user desired precision based on format string | ||||
|             if (!(flags & ImGuiSliderFlags_NoRoundToFormat)) | ||||
| @@ -2732,7 +2736,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ | ||||
|     else | ||||
|     { | ||||
|         // Output grab position so it can be displayed by the caller | ||||
|         float grab_t = ScaleRatioFromValueT<TYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|         float grab_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); | ||||
|         if (axis == ImGuiAxis_Y) | ||||
|             grab_t = 1.0f - grab_t; | ||||
|         const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); | ||||
| @@ -3194,7 +3198,11 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG | ||||
|         // Apply new value (or operations) then clamp | ||||
|         DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL); | ||||
|         if (p_clamp_min || p_clamp_max) | ||||
|         { | ||||
|             if (DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) | ||||
|                 ImSwap(p_clamp_min, p_clamp_max); | ||||
|             DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); | ||||
|         } | ||||
|  | ||||
|         // Only mark as edited if new value is different | ||||
|         value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; | ||||
| @@ -3627,7 +3635,7 @@ void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count) | ||||
|         *dst++ = c; | ||||
|     *dst = '\0'; | ||||
|  | ||||
|     if (CursorPos + bytes_count >= pos) | ||||
|     if (CursorPos >= pos + bytes_count) | ||||
|         CursorPos -= bytes_count; | ||||
|     else if (CursorPos >= pos) | ||||
|         CursorPos = pos; | ||||
| @@ -4432,11 +4440,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ | ||||
|             // Vertical scroll | ||||
|             if (is_multiline) | ||||
|             { | ||||
|                 // Test if cursor is vertically visible | ||||
|                 float scroll_y = draw_window->Scroll.y; | ||||
|                 const float scroll_max_y = ImMax((text_size.y + style.FramePadding.y * 2.0f) - inner_size.y, 0.0f); | ||||
|                 if (cursor_offset.y - g.FontSize < scroll_y) | ||||
|                     scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize); | ||||
|                 else if (cursor_offset.y - inner_size.y >= scroll_y) | ||||
|                     scroll_y = cursor_offset.y - inner_size.y; | ||||
|                     scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f; | ||||
|                 scroll_y = ImClamp(scroll_y, 0.0f, scroll_max_y); | ||||
|                 draw_pos.y += (draw_window->Scroll.y - scroll_y);   // Manipulate cursor pos immediately avoid a frame of lag | ||||
|                 draw_window->Scroll.y = scroll_y; | ||||
|             } | ||||
| @@ -4528,7 +4539,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ | ||||
|  | ||||
|     if (is_multiline) | ||||
|     { | ||||
|         Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line | ||||
|         Dummy(text_size); | ||||
|         EndChild(); | ||||
|         EndGroup(); | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 omar
					omar