Compare commits

..

2 Commits

Author SHA1 Message Date
ocornut
495c1b29a8 Demo: added variety of usage scenarios, hooking Alt, Mouse Wheel, Home, CTRL+Tab demos.
(relate to issues: 456, 2637, 2620, 2891, 3370, 3724, 4828, 5108, 5242, 5641)
2024-11-14 18:19:35 +01:00
ocornut
f1152e5d65 Demo: added SetKeyOwner(), ImGuiInputFlags_LockThisFrame, ImGuiInputFlags_LockUntilRelease demo.
(relate to issues: 456, 2637, 2620, 2891, 3370, 3724, 4828, 5108, 5242, 5641)
2024-11-14 18:19:35 +01:00
5 changed files with 405 additions and 196 deletions

View File

@ -6,9 +6,6 @@
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
@ -19,8 +16,6 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2024-11-15: DirectX12: *BREAKING CHANGE* Changed ImGui_ImplDX12_Init() signature to take a ImGui_ImplDX12_InitInfo struct. Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete).
// 2024-11-15: DirectX12: *BREAKING CHANGE* User is now required to pass function pointers to allocate/free SRV Descriptors. We provide convenience legacy fields to pass a single descriptor, matching the old API, but upcoming features will want multiple.
// 2024-10-23: DirectX12: Unmap() call specify written range. The range is informational and may be used by debug tools.
// 2024-10-07: DirectX12: Changed default texture sampler to Clamp instead of Repeat/Wrap.
// 2024-10-07: DirectX12: Expose selected render state in ImGui_ImplDX12_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks.
@ -55,24 +50,17 @@
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
#endif
// DirectX12 data
// DirectX data
struct ImGui_ImplDX12_RenderBuffers;
struct ImGui_ImplDX12_Texture
{
ID3D12Resource* pTextureResource;
D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle;
D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle;
};
struct ImGui_ImplDX12_Data
{
ImGui_ImplDX12_InitInfo InitInfo;
ID3D12Device* pd3dDevice;
ID3D12RootSignature* pRootSignature;
ID3D12PipelineState* pPipelineState;
DXGI_FORMAT RTVFormat;
ImGui_ImplDX12_Texture FontTexture;
ID3D12Resource* pFontTextureResource;
D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle;
D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle;
ID3D12DescriptorHeap* pd3dSrvDescHeap;
UINT numFramesInFlight;
@ -322,7 +310,6 @@ static void ImGui_ImplDX12_CreateFontsTexture()
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Upload texture to graphics system
ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture;
{
D3D12_HEAP_PROPERTIES props;
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
@ -453,13 +440,13 @@ static void ImGui_ImplDX12_CreateFontsTexture()
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, font_tex->hFontSrvCpuDescHandle);
SafeRelease(font_tex->pTextureResource);
font_tex->pTextureResource = pTexture;
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, bd->hFontSrvCpuDescHandle);
SafeRelease(bd->pFontTextureResource);
bd->pFontTextureResource = pTexture;
}
// Store our identifier
io.Fonts->SetTexID((ImTextureID)font_tex->hFontSrvGpuDescHandle.ptr);
io.Fonts->SetTexID((ImTextureID)bd->hFontSrvGpuDescHandle.ptr);
}
bool ImGui_ImplDX12_CreateDeviceObjects()
@ -705,15 +692,8 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
ImGuiIO& io = ImGui::GetIO();
SafeRelease(bd->pRootSignature);
SafeRelease(bd->pPipelineState);
// Free SRV descriptor used by texture
ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture;
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
if (bd->InitInfo.SrvDescriptorFreeFn != NULL)
#endif
bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, font_tex->hFontSrvCpuDescHandle, font_tex->hFontSrvGpuDescHandle);
SafeRelease(font_tex->pTextureResource);
io.Fonts->SetTexID(0); // We copied bd->hFontSrvGpuDescHandle to io.Fonts->TexID so let's clear that as well.
SafeRelease(bd->pFontTextureResource);
io.Fonts->SetTexID(0); // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
for (UINT i = 0; i < bd->numFramesInFlight; i++)
{
@ -723,7 +703,8 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
}
}
bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
@ -731,39 +712,21 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
// Setup backend capabilities flags
ImGui_ImplDX12_Data* bd = IM_NEW(ImGui_ImplDX12_Data)();
bd->InitInfo = *init_info; // Deep copy
bd->pd3dDevice = init_info->Device;
bd->RTVFormat = init_info->RTVFormat;
bd->numFramesInFlight = init_info->NumFramesInFlight;
bd->pd3dSrvDescHeap = init_info->SrvDescriptorHeap;
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_dx12";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
// Allocate 1 SRV descriptor for the font texture
if (init_info->SrvDescriptorAllocFn != NULL)
{
IM_ASSERT(init_info->SrvDescriptorFreeFn != NULL);
init_info->SrvDescriptorAllocFn(&bd->InitInfo, &bd->FontTexture.hFontSrvCpuDescHandle, &bd->FontTexture.hFontSrvGpuDescHandle);
}
else
{
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
IM_ASSERT(init_info->LegacySingleSrvCpuDescriptor.ptr != 0 && init_info->LegacySingleSrvGpuDescriptor.ptr != 0);
bd->FontTexture.hFontSrvCpuDescHandle = init_info->LegacySingleSrvCpuDescriptor;
bd->FontTexture.hFontSrvGpuDescHandle = init_info->LegacySingleSrvGpuDescriptor;
#else
IM_ASSERT(init_info->SrvDescriptorAllocFn != NULL);
IM_ASSERT(init_info->SrvDescriptorFreeFn != NULL);
#endif
}
bd->pd3dDevice = device;
bd->RTVFormat = rtv_format;
bd->hFontSrvCpuDescHandle = font_srv_cpu_desc_handle;
bd->hFontSrvGpuDescHandle = font_srv_gpu_desc_handle;
bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[num_frames_in_flight];
bd->numFramesInFlight = num_frames_in_flight;
bd->pd3dSrvDescHeap = cbv_srv_heap;
bd->frameIndex = UINT_MAX;
// Create buffers with a default size (they will later be grown as needed)
bd->frameIndex = UINT_MAX;
bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[bd->numFramesInFlight];
for (int i = 0; i < (int)bd->numFramesInFlight; i++)
for (int i = 0; i < num_frames_in_flight; i++)
{
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
fr->IndexBuffer = nullptr;
@ -775,22 +738,6 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
return true;
}
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
// Legacy initialization API Obsoleted in 1.91.5
// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap'
bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle)
{
ImGui_ImplDX12_InitInfo init_info;
init_info.Device = device;
init_info.NumFramesInFlight = num_frames_in_flight;
init_info.RTVFormat = rtv_format;
init_info.SrvDescriptorHeap = srv_descriptor_heap;
init_info.LegacySingleSrvCpuDescriptor = font_srv_cpu_desc_handle;
init_info.LegacySingleSrvGpuDescriptor = font_srv_gpu_desc_handle;;
return ImGui_ImplDX12_Init(&init_info);
}
#endif
void ImGui_ImplDX12_Shutdown()
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
@ -800,7 +747,6 @@ void ImGui_ImplDX12_Shutdown()
// Clean up windows and device objects
ImGui_ImplDX12_InvalidateDeviceObjects();
delete[] bd->pFrameResources;
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;

View File

@ -6,9 +6,6 @@
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
@ -21,42 +18,24 @@
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
#include <dxgiformat.h> // DXGI_FORMAT
#include <d3d12.h> // D3D12_CPU_DESCRIPTOR_HANDLE
// Initialization data, for ImGui_ImplDX12_Init()
struct ImGui_ImplDX12_InitInfo
{
ID3D12Device* Device;
ID3D12CommandQueue* CommandQueue;
int NumFramesInFlight;
DXGI_FORMAT RTVFormat;
void* UserData;
// Allocating SRV descriptors for textures is up to the application, so we provide callbacks.
// (current version of the backend will only allocate one descriptor, future versions will need to allocate more)
ID3D12DescriptorHeap* SrvDescriptorHeap;
void (*SrvDescriptorAllocFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_desc_handle);
void (*SrvDescriptorFreeFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_desc_handle);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
D3D12_CPU_DESCRIPTOR_HANDLE LegacySingleSrvCpuDescriptor; // To facilitate transition from single descriptor to allocator callback, you may use those.
D3D12_GPU_DESCRIPTOR_HANDLE LegacySingleSrvGpuDescriptor;
#endif
ImGui_ImplDX12_InitInfo() { memset(this, 0, sizeof(*this)); }
};
struct ID3D12Device;
struct ID3D12DescriptorHeap;
struct ID3D12GraphicsCommandList;
struct D3D12_CPU_DESCRIPTOR_HANDLE;
struct D3D12_GPU_DESCRIPTOR_HANDLE;
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* info);
// Before calling the render function, caller must prepare the command list by resetting it and setting the appropriate
// render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle.
// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture.
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle);
IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
// Legacy initialization API Obsoleted in 1.91.5
// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap'
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle);
#endif
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();

View File

@ -41,20 +41,10 @@ HOW TO UPDATE?
Breaking changes:
- Backends: DX12: Changed ImGui_ImplDX12_Init() signature to take a
ImGui_ImplDX12_InitInfo struct.
- Using the new API, application is now required to pass function pointers
to allocate/free SRV Descriptors.
- We provide convenience legacy fields to pass a single descriptor,
matching the old API, but upcoming features will want multiple.
- Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete).
Other changes:
- Error Handling: fixed cases where recoverable error handling would crash when
processing errors outside of the NewFrame()..EndFrame() scope. (#1651)
- Examples: Win32+DX12: Using a basic free-list allocator to manage multiple
SRV descriptors.
-----------------------------------------------------------------------

View File

@ -22,70 +22,23 @@
#pragma comment(lib, "dxguid.lib")
#endif
// Config for example app
static const int APP_NUM_FRAMES_IN_FLIGHT = 3;
static const int APP_NUM_BACK_BUFFERS = 3;
static const int APP_SRV_HEAP_SIZE = 64;
#include "imgui_internal.h"
struct FrameContext
{
ID3D12CommandAllocator* CommandAllocator;
UINT64 FenceValue;
};
// Simple free list based allocator
struct ExampleDescriptorHeapAllocator
{
ID3D12DescriptorHeap* Heap = nullptr;
D3D12_DESCRIPTOR_HEAP_TYPE HeapType = D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES;
D3D12_CPU_DESCRIPTOR_HANDLE HeapStartCpu;
D3D12_GPU_DESCRIPTOR_HANDLE HeapStartGpu;
UINT HeapHandleIncrement;
ImVector<int> FreeIndices;
void Create(ID3D12Device* device, ID3D12DescriptorHeap* heap)
{
IM_ASSERT(Heap == nullptr && FreeIndices.empty());
Heap = heap;
D3D12_DESCRIPTOR_HEAP_DESC desc = heap->GetDesc();
HeapType = desc.Type;
HeapStartCpu = Heap->GetCPUDescriptorHandleForHeapStart();
HeapStartGpu = Heap->GetGPUDescriptorHandleForHeapStart();
HeapHandleIncrement = device->GetDescriptorHandleIncrementSize(HeapType);
FreeIndices.reserve((int)desc.NumDescriptors);
for (int n = desc.NumDescriptors; n > 0; n--)
FreeIndices.push_back(n);
}
void Destroy()
{
Heap = NULL;
FreeIndices.clear();
}
void Alloc(D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_desc_handle)
{
IM_ASSERT(FreeIndices.Size > 0);
int idx = FreeIndices.back();
FreeIndices.pop_back();
out_cpu_desc_handle->ptr = HeapStartCpu.ptr + (idx * HeapHandleIncrement);
out_gpu_desc_handle->ptr = HeapStartGpu.ptr + (idx * HeapHandleIncrement);
}
void Free(D3D12_CPU_DESCRIPTOR_HANDLE out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE out_gpu_desc_handle)
{
int cpu_idx = (int)((out_cpu_desc_handle.ptr - HeapStartCpu.ptr) / HeapHandleIncrement);
int gpu_idx = (int)((out_gpu_desc_handle.ptr - HeapStartGpu.ptr) / HeapHandleIncrement);
IM_ASSERT(cpu_idx == gpu_idx);
FreeIndices.push_back(cpu_idx);
}
ID3D12CommandAllocator* CommandAllocator;
UINT64 FenceValue;
};
// Data
static FrameContext g_frameContext[APP_NUM_FRAMES_IN_FLIGHT] = {};
static int const NUM_FRAMES_IN_FLIGHT = 3;
static FrameContext g_frameContext[NUM_FRAMES_IN_FLIGHT] = {};
static UINT g_frameIndex = 0;
static int const NUM_BACK_BUFFERS = 3;
static ID3D12Device* g_pd3dDevice = nullptr;
static ID3D12DescriptorHeap* g_pd3dRtvDescHeap = nullptr;
static ID3D12DescriptorHeap* g_pd3dSrvDescHeap = nullptr;
static ExampleDescriptorHeapAllocator g_pd3dSrvDescHeapAlloc;
static ID3D12CommandQueue* g_pd3dCommandQueue = nullptr;
static ID3D12GraphicsCommandList* g_pd3dCommandList = nullptr;
static ID3D12Fence* g_fence = nullptr;
@ -94,8 +47,8 @@ static UINT64 g_fenceLastSignaledValue = 0;
static IDXGISwapChain3* g_pSwapChain = nullptr;
static bool g_SwapChainOccluded = false;
static HANDLE g_hSwapChainWaitableObject = nullptr;
static ID3D12Resource* g_mainRenderTargetResource[APP_NUM_BACK_BUFFERS] = {};
static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[APP_NUM_BACK_BUFFERS] = {};
static ID3D12Resource* g_mainRenderTargetResource[NUM_BACK_BUFFERS] = {};
static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[NUM_BACK_BUFFERS] = {};
// Forward declarations of helper functions
bool CreateDeviceD3D(HWND hWnd);
@ -140,18 +93,10 @@ int main(int, char**)
// Setup Platform/Renderer backends
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplDX12_InitInfo init_info = {};
init_info.Device = g_pd3dDevice;
init_info.CommandQueue = g_pd3dCommandQueue;
init_info.NumFramesInFlight = APP_NUM_FRAMES_IN_FLIGHT;
init_info.RTVFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
// Allocating SRV descriptors (for textures) is up to the application, so we provide callbacks.
// (current version of the backend will only allocate one descriptor, future versions will need to allocate more)
init_info.SrvDescriptorHeap = g_pd3dSrvDescHeap;
init_info.SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle) { return g_pd3dSrvDescHeapAlloc.Alloc(out_cpu_handle, out_gpu_handle); };
init_info.SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle) { return g_pd3dSrvDescHeapAlloc.Free(cpu_handle, gpu_handle); };
ImGui_ImplDX12_Init(&init_info);
ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT,
DXGI_FORMAT_R8G8B8A8_UNORM, g_pd3dSrvDescHeap,
g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(),
g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart());
// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
@ -304,7 +249,7 @@ bool CreateDeviceD3D(HWND hWnd)
DXGI_SWAP_CHAIN_DESC1 sd;
{
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = APP_NUM_BACK_BUFFERS;
sd.BufferCount = NUM_BACK_BUFFERS;
sd.Width = 0;
sd.Height = 0;
sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
@ -347,7 +292,7 @@ bool CreateDeviceD3D(HWND hWnd)
{
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
desc.NumDescriptors = APP_NUM_BACK_BUFFERS;
desc.NumDescriptors = NUM_BACK_BUFFERS;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
desc.NodeMask = 1;
if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dRtvDescHeap)) != S_OK)
@ -355,7 +300,7 @@ bool CreateDeviceD3D(HWND hWnd)
SIZE_T rtvDescriptorSize = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->GetCPUDescriptorHandleForHeapStart();
for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++)
for (UINT i = 0; i < NUM_BACK_BUFFERS; i++)
{
g_mainRenderTargetDescriptor[i] = rtvHandle;
rtvHandle.ptr += rtvDescriptorSize;
@ -365,11 +310,10 @@ bool CreateDeviceD3D(HWND hWnd)
{
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
desc.NumDescriptors = APP_SRV_HEAP_SIZE;
desc.NumDescriptors = 1;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dSrvDescHeap)) != S_OK)
return false;
g_pd3dSrvDescHeapAlloc.Create(g_pd3dDevice, g_pd3dSrvDescHeap);
}
{
@ -381,7 +325,7 @@ bool CreateDeviceD3D(HWND hWnd)
return false;
}
for (UINT i = 0; i < APP_NUM_FRAMES_IN_FLIGHT; i++)
for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++)
if (g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&g_frameContext[i].CommandAllocator)) != S_OK)
return false;
@ -407,7 +351,7 @@ bool CreateDeviceD3D(HWND hWnd)
return false;
swapChain1->Release();
dxgiFactory->Release();
g_pSwapChain->SetMaximumFrameLatency(APP_NUM_BACK_BUFFERS);
g_pSwapChain->SetMaximumFrameLatency(NUM_BACK_BUFFERS);
g_hSwapChainWaitableObject = g_pSwapChain->GetFrameLatencyWaitableObject();
}
@ -420,7 +364,7 @@ void CleanupDeviceD3D()
CleanupRenderTarget();
if (g_pSwapChain) { g_pSwapChain->SetFullscreenState(false, nullptr); g_pSwapChain->Release(); g_pSwapChain = nullptr; }
if (g_hSwapChainWaitableObject != nullptr) { CloseHandle(g_hSwapChainWaitableObject); }
for (UINT i = 0; i < APP_NUM_FRAMES_IN_FLIGHT; i++)
for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++)
if (g_frameContext[i].CommandAllocator) { g_frameContext[i].CommandAllocator->Release(); g_frameContext[i].CommandAllocator = nullptr; }
if (g_pd3dCommandQueue) { g_pd3dCommandQueue->Release(); g_pd3dCommandQueue = nullptr; }
if (g_pd3dCommandList) { g_pd3dCommandList->Release(); g_pd3dCommandList = nullptr; }
@ -442,7 +386,7 @@ void CleanupDeviceD3D()
void CreateRenderTarget()
{
for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++)
for (UINT i = 0; i < NUM_BACK_BUFFERS; i++)
{
ID3D12Resource* pBackBuffer = nullptr;
g_pSwapChain->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer));
@ -455,13 +399,13 @@ void CleanupRenderTarget()
{
WaitForLastSubmittedFrame();
for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++)
for (UINT i = 0; i < NUM_BACK_BUFFERS; i++)
if (g_mainRenderTargetResource[i]) { g_mainRenderTargetResource[i]->Release(); g_mainRenderTargetResource[i] = nullptr; }
}
void WaitForLastSubmittedFrame()
{
FrameContext* frameCtx = &g_frameContext[g_frameIndex % APP_NUM_FRAMES_IN_FLIGHT];
FrameContext* frameCtx = &g_frameContext[g_frameIndex % NUM_FRAMES_IN_FLIGHT];
UINT64 fenceValue = frameCtx->FenceValue;
if (fenceValue == 0)
@ -483,7 +427,7 @@ FrameContext* WaitForNextFrameResources()
HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, nullptr };
DWORD numWaitableObjects = 1;
FrameContext* frameCtx = &g_frameContext[nextFrameIndex % APP_NUM_FRAMES_IN_FLIGHT];
FrameContext* frameCtx = &g_frameContext[nextFrameIndex % NUM_FRAMES_IN_FLIGHT];
UINT64 fenceValue = frameCtx->FenceValue;
if (fenceValue != 0) // means no fence was signaled
{

View File

@ -7339,6 +7339,8 @@ static void ShowDemoWindowColumns()
// [SECTION] ShowDemoWindowInputs()
//-----------------------------------------------------------------------------
#include "imgui_internal.h" // FIXME Until the new key owner/routing system are in public API this section of the demo needs internal (and is kept in a branch).
static void ShowDemoWindowInputs()
{
IMGUI_DEMO_MARKER("Inputs & Focus");
@ -7518,7 +7520,355 @@ static void ShowDemoWindowInputs()
}
ImGui::EndChild();
ImGui::PopStyleColor();
ImGui::TreePop();
}
// Ownership, Routings
IMGUI_DEMO_MARKER("Inputs & Focus/Key Ownership");
if (ImGui::TreeNode("Key Ownership"))
{
HelpMarker("See 'Tools->Metrics/Debugger->Inputs' to visualize ownership/routing data.");
// Demonstrate basic key ownership system
// Standard widgets all claim and test for key ownership
// (note that the ActiveId and HoveredId systems also generally prevents multiple items from interacting, but at a different level)
if (ImGui::TreeNode("1. Standard widgets taking input ownership"))
{
HelpMarker("Standard widgets claim and test for key ownership.\n\n\"Keys\" include mouse buttons, gamepad axises etc.");
const ImGuiKey key = ImGuiKey_MouseLeft; // Note how mouse and gamepad are also included in ImGuiKey: same data type for all.
const char* key_name = ImGui::GetKeyName(key);
ImGui::Text("Press '%s'", key_name);
ImGui::Text("1st read: (button)");
ImGui::Button("Click and Hold Me Tight!");
// Assume this is another piece of code running later.
// The *default* value for owner is ImGuiKeyOwner_Any, same as calling the simplified function:
// IsKeyDown(key) == IsKeyDown(key, ImGuiKeyOwner_Any)
// IsKeyPressed(key) == IsKeyPressed(key, ImGuiKeyOwner_Any)
// But notice the "bool repeat = true" parameter in old signature 'IsKeyPressed(key, repeat)'
// with the new signature becomes 'IsKeyPressed(key, owner, ImGuiInputFlags_Repeat)'
ImGui::Text("2nd read: (NOT owner-aware)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key) ? "PRESSED!" : "..");
ImGui::Text("3rd read: (owner-aware: ImGuiKeyOwner_NoOwner)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key, ImGuiKeyOwner_NoOwner) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, ImGuiInputFlags_Repeat, ImGuiKeyOwner_NoOwner) ? "PRESSED!" : "..");
ImGuiID another_owner = ImGui::GetID("AnotherItem");
ImGui::Text("4nd read: (owner-aware: different owner)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key, another_owner) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, ImGuiInputFlags_Repeat, another_owner) ? "PRESSED!" : "..");
ImGui::TreePop();
}
if (ImGui::TreeNode("2. Calling SetKeyOwner()"))
{
const ImGuiKey key = ImGuiKey_A;
const char* key_name = ImGui::GetKeyName(key);
ImGui::Text("Press '%s'", key_name);
ImGui::Text("1st read:");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, false) ? "PRESSED!" : "..");
ImGui::Text("...when pressed, call SetKeyOwner() with an owner ID.");
ImGuiID owner_1 = ImGui::GetID("MyItemID");
if (ImGui::IsKeyPressed(key, ImGuiInputFlags_Repeat, owner_1))
ImGui::SetKeyOwner(key, owner_1);
// Assume this is another piece of code running later.
// (same comments as in section 1)
ImGui::Text("2nd read: (NOT owner-aware)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key) ? "PRESSED!" : "..");
ImGui::Text("3rd read: (owner-aware: ImGuiKeyOwner_NoOwner)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key, ImGuiKeyOwner_NoOwner) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, ImGuiInputFlags_Repeat, ImGuiKeyOwner_NoOwner) ? "PRESSED!" : "..");
ImGuiID another_owner = ImGui::GetID("AnotherItem");
ImGui::Text("4th read: (owner-aware: different owner)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key, another_owner) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, ImGuiInputFlags_Repeat, another_owner) ? "PRESSED!" : "..");
ImGui::TreePop();
}
// Demonstrate using SetKeyOwner() with ImGuiInputFlags_LockThisFrame / ImGuiInputFlags_LockUntilRelease flags.
// - Using an owner id solves all/most cases as long as everyone is "owner-id-aware",
// meaning they call the long form of IsKeyXXX function. This is the preferred way to do things.
// - Using ImGuiInputFlags_LockXXXX flags is a way to prevent code that is NOT owner-id-aware from accessing the key.
// Think of it as "eating" a key completely: only same owner ID can access the key/button.
if (ImGui::TreeNode("3. Calling SetKeyOwner() with ImGuiInputFlags_LockXXX flags for non-owner-aware code"))
{
const ImGuiKey key = ImGuiKey_B;
const char* key_name = ImGui::GetKeyName(key);
ImGui::Text("Press '%s'", key_name);
static bool lock_this_frame = false;
static bool lock_until_release = false;
ImGui::Text("1st read:");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, false) ? "PRESSED!" : "..");
ImGui::Text("...when pressed, call SetKeyOwner() with:");
ImGui::Checkbox("ImGuiInputFlags_LockThisFrame", &lock_this_frame);
ImGui::Checkbox("ImGuiInputFlags_LockUntilRelease", &lock_until_release);
if (ImGui::IsKeyPressed(key, false) && (lock_this_frame || lock_until_release))
ImGui::SetKeyOwner(key, 0, (lock_this_frame ? ImGuiInputFlags_LockThisFrame : 0) | (lock_until_release ? ImGuiInputFlags_LockUntilRelease : 0));
// Assume this is another piece of code running later. The calls are not owner-aware,
// due to the lock they won't be able to see the key.
ImGui::Text("2nd read: (NOT owner-aware)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, false) ? "PRESSED!" : "..");
ImGui::TreePop();
}
// Miscellaneous examples
if (ImGui::TreeNode("Usage Scenarios"))
{
// We use colored buttons for the demo but this would generally apply to any widget.
const ImVec2 button_sz(60.0f, 60.0f);
const ImGuiColorEditFlags button_flags = ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop;
if (ImGui::TreeNode("1. Claiming Mouse Wheel"))
{
static float value1 = 0.0f;
ImGui::Text("%.2f", value1);
ImGui::SameLine();
HelpMarker("Hover button and use mouse wheel: window scrolling won't be activated.");
ImGui::ColorButton("Item1", ImVec4(0.4f, 0.4f, 0.8f, 1.0f), button_flags, button_sz);
ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY);
if (ImGui::IsItemHovered() || ImGui::IsItemActive())
value1 += io.MouseWheel;
static float value2 = 0.0f;
ImGui::Text("%.2f", value2);
ImGui::SameLine();
HelpMarker("Hold button and use mouse wheel: window scrolling won't be activated.");
ImGui::ColorButton("Item2", ImVec4(0.4f, 0.4f, 0.8f, 1.0f), button_flags, button_sz);
ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY, ImGuiInputFlags_CondActive);
if (ImGui::IsItemActive())
value2 += io.MouseWheel;
ImGui::TreePop();
}
if (ImGui::TreeNode("2. Claiming Alt key"))
{
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
static float spinner0 = 0.0f;
ImGui::Text("%.3f", spinner0);
ImGui::SameLine();
HelpMarker("Click, hold ALT drag to tweak value. Notice that Alt doesn't move focus to menu bar.");
ImGui::Button("Spin me", button_sz);
if (ImGui::IsItemActive())
{
ImGui::SetKeyOwner(ImGuiMod_Alt, ImGui::GetItemID());
if (ImGui::IsKeyDown(ImGuiMod_Alt)) // Poll on Active: we don't need to check for ownership of ImGuiMod_Alt since we know we unconditionally own it.
spinner0 += io.MouseDelta.x;
}
// When using of keys is conditioned by item being hovered or active,
// it creates a natural exclusivity, since only one item can be hovered or active.
// SetItemKeyOwner(...) is a shortcut for doing 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(..., GetItemID()); }'
static int value1 = 0;
ImGui::Text("%d", value1);
ImGui::SameLine();
HelpMarker("Item1 claims ALT key when Hovered or Active, counter increase when pressing ALT while Hovered.");
ImGui::Button("Item1", button_sz);
ImGui::SetItemKeyOwner(ImGuiMod_Alt); // Claim Alt on Hover and Active
if (ImGui::IsItemHovered() && ImGui::IsKeyPressed(ImGuiMod_Alt, false)) // Poll on Hover: we don't need to check for ownership of ImGuiMod_Alt since we know we unconditionally own it.
value1++;
ImGui::TreePop();
}
// Routing options are only available for Shortcuts (not Key)
// Using shortcut functions with only ImGuiMod_Alt means that other modifiers e.g. CTRL+ALT+S won't be affected, which is often desirable.
// Here we use ImGuiInputFlags_RouteFocused which will claim the Alt shortcut when the window is focused.
// Notice that opening this node will claim Alt, therefore change the behavior of the key checks in section (2) above.
if (ImGui::TreeNode("3. Claiming Alt shortcut"))
{
// Using Shortcut() with ImGuiInputFlags_RouteFocused means we react when parent window is focused.
// - Passing 0 (== ImGuiKeyOwner_Any) means current location will be used to identify.
// As both calls are from the same location, both items will receive the shortcut.
// - Passing GetItemID() here means they both have their unique id,
// - Item2 will only receive the shortcut when parent window is focused.
// - Item3 will only receive the shortcut when active.
// Not passing an item id would use current location as id so both items will always receive shortcut.
static bool use_shared_owner = false;
ImGui::Checkbox("Item2 and Item3 use same owner/location", &use_shared_owner);
static int value2 = 0;
ImGui::Text("%d", value2);
ImGui::SameLine();
HelpMarker("Item2 reads ALT shortcut when its parent window is focused.");
ImGui::Button("Item2", button_sz);
if (ImGui::Shortcut(ImGuiMod_Alt, 0, use_shared_owner ? 0 : ImGui::GetItemID()))
value2++;
static int value3 = 0;
ImGui::Text("%d", value3);
ImGui::SameLine();
HelpMarker("Item3 reads ALT shortcut when its parent window is focused AND it is active. Therefore, only active previous button will get the shortcut");
ImGui::Button("Item3", button_sz);
if (ImGui::Shortcut(ImGuiMod_Alt, 0, use_shared_owner ? 0 : ImGui::GetItemID()))
value3++;
ImGui::TreePop();
}
if (ImGui::TreeNode("4. Claiming Home key globally"))
{
static bool enable_home_robbery = false;
static int home_presses = 0;
ImGui::Checkbox("Global steal ImGuiKey_Home", &enable_home_robbery);
ImGui::Text("Home presses: %d", home_presses);
if (enable_home_robbery)
{
// Claim ownership is enough to keep Key away from main library behavior or any owner-aware code.
// - We optionally use the ImGuiInputFlags_LockUntilRelease to keep key away from code that is not owner-aware,
// but Dear ImGui itself is so that's not technically needed (unless you are stealing from another piece of code).
ImGuiID robber_id = ImGui::GetID("Some Identifier");
ImGui::SetKeyOwner(ImGuiKey_Home, robber_id, ImGuiInputFlags_LockUntilRelease);
if (ImGui::IsKeyPressed(ImGuiKey_Home, ImGuiInputFlags_Repeat, robber_id)) // We unconditionally own the key so no need to test for ownership
home_presses++;
}
ImGui::TreePop();
}
if (ImGui::TreeNode("5. Claiming CTRL+A shortcut globally"))
{
// Using a priority of ImGuiInputFlags_RouteGlobal + RouteOverActive means we takes away even from an active item (e.g. InputText)
// This is better covered in "Shortcut Routing basics" above.
static bool enable_ctrl_a_robbery = false;
static int ctrl_a_presses = 0;
ImGui::Checkbox("Global steal CTRL+A", &enable_ctrl_a_robbery);
ImGui::Text("CTRL+A presses: %d", ctrl_a_presses);
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_A, enable_ctrl_a_robbery ? ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive : ImGuiInputFlags_RouteAlways))
ctrl_a_presses++;
ImGui::TreePop();
}
if (ImGui::TreeNode("6. Disable ESC key from InputText()"))
{
static char buf[9];
ImGui::InputText("Text", buf, IM_ARRAYSIZE(buf));
// - If you don't need to use the key, you can use 'owner_id=0', 'flags=ImGuiInputFlags_LockXXX'
// as a convenience to hide the key from everyone.
// - If you need to use the key yourself, you need to use any arbitrary ID, and then use this ID to read the key.
// e.g. ImGui::SetKeyOwner(ImGuiKey_Escape, ImGui::GetID("robber")); + later use same ID to access the key.
if (ImGui::IsItemActive())
ImGui::SetKeyOwner(ImGuiKey_Escape, 0, ImGuiInputFlags_LockUntilRelease);
ImGui::TreePop();
}
if (ImGui::TreeNode("7. Claiming ESC key away from InputText()"))
{
static char buf[9];
ImGui::InputText("Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_EscapeClearsAll);
if (ImGui::IsItemActive())
{
// Using a route which is higher priority than one claimed the ActiveId
ImGuiID robber_id = ImGui::GetID("robber");
if (ImGui::Shortcut(ImGuiKey_Escape, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive, robber_id))
{
strcpy(buf, "Esc!");
ImGui::ClearActiveID();
}
}
ImGui::TreePop();
}
if (ImGui::TreeNode("8. Claiming ESC away from nav logic (e.g. exiting a child)"))
{
ImGui::BeginChild("child", ImVec2(-FLT_MIN, 50), true);
ImGui::Button("Button in child");
if (ImGui::IsWindowFocused())
ImGui::SetKeyOwner(ImGuiKey_Escape, ImGui::GetID("")); // any id
ImGui::EndChild();
ImGui::TreePop();
}
if (ImGui::TreeNode("9. Claiming Tab, CTRL+Tab"))
{
static int mode = 0;
static int counter = 0;
HelpMarker("Showcasing many variants as a recap.\nPlease read code and comments carefully!");
const char* mode_names[] = { "None", "Disable Tab key (item)", "Disable Tab key (global)", "Disable CTRL+Tab (global)", "Disable CTRL+Tab (if focused)", "Read CTRL+Tab (global)", "Replace CTRL+Tab (global)", "Replace CTRL+Tab (if focused)" };
ImGui::Combo("Operation Mode", &mode, mode_names, IM_ARRAYSIZE(mode_names));
ImGui::Text("Counter = %d", counter);
switch (mode)
{
case 1:
// Item take ownership of Tab key when hovered/active (meaning ALL uses of Tab will be disabled, not just CTRL+Tab)
ImGui::Button("This Button Steals The Tab Key");
ImGui::SetItemKeyOwner(ImGuiKey_Tab);
ImGui::SameLine();
HelpMarker("While hovering or activating this button, TAB key is stolen (e.g. won't tab out into other systems)");
break;
case 2:
// Take ownership of Tab key (meaning ALL uses of Tab will be disabled, not just CTRL+Tab)
ImGui::SetKeyOwner(ImGuiKey_Tab, ImGui::GetID("some-id"));
break;
case 3:
// Disable CTRL+Tab shortcuts (global): assign an owner to steal the route to our two shortcuts
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiKey_Tab, 0, ImGui::GetID("some-id"));
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, 0, ImGui::GetID("some-id"));
break;
case 4:
// Disable CTRL+Tab shortcuts (if focused): assign an owner to steal the route to our two shortcuts, applies focus testing so will only apply if window is in focus chain
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiKey_Tab, ImGuiInputFlags_RouteFocused, ImGui::GetID("some-id"));
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, ImGuiInputFlags_RouteFocused, ImGui::GetID("some-id"));
break;
case 5:
// Read CTRL+Tab (global): reading keys without interfering with any behaviors (need to specify ImGuiInputFlags_RouteAlways as other policies will interfere)
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_Tab, ImGuiInputFlags_RouteAlways, ImGuiKeyOwner_Any))
counter++;
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, ImGuiInputFlags_RouteAlways, ImGuiKeyOwner_Any))
counter--;
break;
case 6:
{
// Replace CTRL+Tab (global)
// - We steal the route and assign it to our ID (so core system won't access it). Our reading queries now need to specify that ID.
ImGuiID id = ImGui::GetID("My-Ctrl-Tab-Handler");
//ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiKey_Tab, id, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive);
//ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, id, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive);
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_Tab, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive, id))
counter++; // You could perform some other action here.
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive, id))
counter--;
break;
}
case 7:
// Replace CTRL+Tab (if focused)
// - Passing ImGuiInputFlags_RouteFocused will test for focus and assign a route using a default owner id based on location (so we can use 0 as id)
// - This would also work if we replaced 0 with ImGui::GetID("My-Ctrl-Tab-Handler")
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_Tab))
counter++; // You could perform some other action here.
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab))
counter--;
break;
}
static char buf[8] = "";
ImGui::InputTextWithHint("Dummy", "(dummy input text to test effect of Tabbing)", buf, IM_ARRAYSIZE(buf));
ImGui::TreePop();
}
ImGui::TreePop();
}
ImGui::TreePop();
}