diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 4bbcbcbdb..12fe6d277 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -168,11 +168,9 @@ LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) io.AddInputCharacter((unsigned short)wParam); return true; case WM_DESTROY: - { - Cleanup(); - PostQuitMessage(0); - return 0; - } + Cleanup(); + PostQuitMessage(0); + return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); } @@ -180,14 +178,14 @@ LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) // Notify OS Input Method Editor of text input position (e.g. when using Japanese/Chinese inputs, otherwise this isn't needed) static void ImImpl_ImeSetInputScreenPosFn(int x, int y) { - if (HIMC himc = ImmGetContext(hWnd)) - { - COMPOSITIONFORM cf; - cf.ptCurrentPos.x = x; - cf.ptCurrentPos.y = y; - cf.dwStyle = CFS_FORCE_POSITION; - ImmSetCompositionWindow(himc, &cf); - } + if (HIMC himc = ImmGetContext(hWnd)) + { + COMPOSITIONFORM cf; + cf.ptCurrentPos.x = x; + cf.ptCurrentPos.y = y; + cf.dwStyle = CFS_FORCE_POSITION; + ImmSetCompositionWindow(himc, &cf); + } } void InitImGui() @@ -218,7 +216,7 @@ void InitImGui() io.KeyMap[ImGuiKey_Z] = 'Z'; io.RenderDrawListsFn = ImImpl_RenderDrawLists; - io.ImeSetInputScreenPosFn = ImImpl_ImeSetInputScreenPosFn; + io.ImeSetInputScreenPosFn = ImImpl_ImeSetInputScreenPosFn; // Create the vertex buffer if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) @@ -310,36 +308,31 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int) UpdateImGui(); - // Create a simple window - // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug" static bool show_test_window = true; static bool show_another_window = false; - static float f; - ImGui::Text("Hello, world!"); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); - show_test_window ^= ImGui::Button("Test Window"); - show_another_window ^= ImGui::Button("Another Window"); - // Calculate and show framerate - static float ms_per_frame[120] = { 0 }; - static int ms_per_frame_idx = 0; - static float ms_per_frame_accum = 0.0f; - ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx]; - ms_per_frame[ms_per_frame_idx] = ImGui::GetIO().DeltaTime * 1000.0f; - ms_per_frame_accum += ms_per_frame[ms_per_frame_idx]; - ms_per_frame_idx = (ms_per_frame_idx + 1) % 120; - const float ms_per_frame_avg = ms_per_frame_accum / 120; - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg); - - // Show the ImGui test window - // Most of user example code is in ImGui::ShowTestWindow() - if (show_test_window) + // 1. Show a simple window + // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug" { - ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly! - ImGui::ShowTestWindow(&show_test_window); + static float f; + ImGui::Text("Hello, world!"); + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); + show_test_window ^= ImGui::Button("Test Window"); + show_another_window ^= ImGui::Button("Another Window"); + + // Calculate and show framerate + static float ms_per_frame[120] = { 0 }; + static int ms_per_frame_idx = 0; + static float ms_per_frame_accum = 0.0f; + ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx]; + ms_per_frame[ms_per_frame_idx] = ImGui::GetIO().DeltaTime * 1000.0f; + ms_per_frame_accum += ms_per_frame[ms_per_frame_idx]; + ms_per_frame_idx = (ms_per_frame_idx + 1) % 120; + const float ms_per_frame_avg = ms_per_frame_accum / 120; + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg); } - // Show another simple window + // 2. Show another simple window, this time using an explicit Begin/End pair if (show_another_window) { ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100)); @@ -347,6 +340,13 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int) ImGui::End(); } + // 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow() + if (show_test_window) + { + ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly! + ImGui::ShowTestWindow(&show_test_window); + } + // Rendering g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false); diff --git a/examples/opengl_example/main.cpp b/examples/opengl_example/main.cpp index 3007c05ab..5549980c1 100644 --- a/examples/opengl_example/main.cpp +++ b/examples/opengl_example/main.cpp @@ -19,6 +19,7 @@ static GLFWwindow* window; static GLuint fontTex; +static bool mousePressed[2] = { false, false }; static ImVec2 mousePosScale(1.0f, 1.0f); // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) @@ -94,15 +95,15 @@ static void ImImpl_SetClipboardTextFn(const char* text) // Notify OS Input Method Editor of text input position (e.g. when using Japanese/Chinese inputs, otherwise this isn't needed) static void ImImpl_ImeSetInputScreenPosFn(int x, int y) { - HWND hwnd = glfwGetWin32Window(window); - if (HIMC himc = ImmGetContext(hwnd)) - { - COMPOSITIONFORM cf; - cf.ptCurrentPos.x = x; - cf.ptCurrentPos.y = y; - cf.dwStyle = CFS_FORCE_POSITION; - ImmSetCompositionWindow(himc, &cf); - } + HWND hwnd = glfwGetWin32Window(window); + if (HIMC himc = ImmGetContext(hwnd)) + { + COMPOSITIONFORM cf; + cf.ptCurrentPos.x = x; + cf.ptCurrentPos.y = y; + cf.dwStyle = CFS_FORCE_POSITION; + ImmSetCompositionWindow(himc, &cf); + } } #endif @@ -112,6 +113,12 @@ static void glfw_error_callback(int error, const char* description) fputs(description, stderr); } +static void glfw_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + if (action == GLFW_PRESS && button >= 0 && button < 2) + mousePressed[button] = true; +} + static void glfw_scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { ImGuiIO& io = ImGui::GetIO(); @@ -147,6 +154,7 @@ void InitGL() window = glfwCreateWindow(1280, 720, "ImGui OpenGL example", NULL, NULL); glfwMakeContextCurrent(window); glfwSetKeyCallback(window, glfw_key_callback); + glfwSetMouseButtonCallback(window, glfw_mouse_button_callback); glfwSetScrollCallback(window, glfw_scroll_callback); glfwSetCharCallback(window, glfw_char_callback); @@ -188,7 +196,7 @@ void InitImGui() io.SetClipboardTextFn = ImImpl_SetClipboardTextFn; io.GetClipboardTextFn = ImImpl_GetClipboardTextFn; #ifdef _MSC_VER - io.ImeSetInputScreenPosFn = ImImpl_ImeSetInputScreenPosFn; + io.ImeSetInputScreenPosFn = ImImpl_ImeSetInputScreenPosFn; #endif // Load font texture @@ -198,35 +206,35 @@ void InitImGui() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); #if 1 - // Default font (embedded in code) + // Default font (embedded in code) const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); int tex_x, tex_y, tex_comp; void* tex_data = stbi_load_from_memory((const unsigned char*)png_data, (int)png_size, &tex_x, &tex_y, &tex_comp, 0); - IM_ASSERT(tex_data != NULL); + IM_ASSERT(tex_data != NULL); #else - // Custom font from filesystem - io.Font = new ImBitmapFont(); - io.Font->LoadFromFile("../../extra_fonts/mplus-2m-medium_18.fnt"); - IM_ASSERT(io.Font->IsLoaded()); + // Custom font from filesystem + io.Font = new ImBitmapFont(); + io.Font->LoadFromFile("../../extra_fonts/mplus-2m-medium_18.fnt"); + IM_ASSERT(io.Font->IsLoaded()); int tex_x, tex_y, tex_comp; - void* tex_data = stbi_load("../../extra_fonts/mplus-2m-medium_18.png", &tex_x, &tex_y, &tex_comp, 0); - IM_ASSERT(tex_data != NULL); - - // Automatically find white pixel from the texture we just loaded - // (io.FontTexUvForWhite needs to contains UV coordinates pointing to a white pixel in order to render solid objects) - for (int tex_data_off = 0; tex_data_off < tex_x*tex_y; tex_data_off++) - if (((unsigned int*)tex_data)[tex_data_off] == 0xffffffff) - { - io.FontTexUvForWhite = ImVec2((float)(tex_data_off % tex_x)/(tex_x), (float)(tex_data_off / tex_x)/(tex_y)); - break; - } + void* tex_data = stbi_load("../../extra_fonts/mplus-2m-medium_18.png", &tex_x, &tex_y, &tex_comp, 0); + IM_ASSERT(tex_data != NULL); + + // Automatically find white pixel from the texture we just loaded + // (io.FontTexUvForWhite needs to contains UV coordinates pointing to a white pixel in order to render solid objects) + for (int tex_data_off = 0; tex_data_off < tex_x*tex_y; tex_data_off++) + if (((unsigned int*)tex_data)[tex_data_off] == 0xffffffff) + { + io.FontTexUvForWhite = ImVec2((float)(tex_data_off % tex_x)/(tex_x), (float)(tex_data_off / tex_x)/(tex_y)); + break; + } #endif glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_x, tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_data); - stbi_image_free(tex_data); + stbi_image_free(tex_data); } void UpdateImGui() @@ -243,9 +251,9 @@ void UpdateImGui() // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) double mouse_x, mouse_y; glfwGetCursorPos(window, &mouse_x, &mouse_y); - io.MousePos = ImVec2((float)mouse_x * mousePosScale.x, (float)mouse_y * mousePosScale.y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - io.MouseDown[0] = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != 0; - io.MouseDown[1] = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != 0; + io.MousePos = ImVec2((float)mouse_x * mousePosScale.x, (float)mouse_y * mousePosScale.y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) + io.MouseDown[0] = mousePressed[0] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + io.MouseDown[1] = mousePressed[1] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != 0; // Start the frame ImGui::NewFrame(); @@ -260,40 +268,36 @@ int main(int argc, char** argv) while (!glfwWindowShouldClose(window)) { ImGuiIO& io = ImGui::GetIO(); + mousePressed[0] = mousePressed[1] = false; io.MouseWheel = 0; glfwPollEvents(); UpdateImGui(); - // Create a simple window - // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug" static bool show_test_window = true; static bool show_another_window = false; - static float f; - ImGui::Text("Hello, world!"); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); - show_test_window ^= ImGui::Button("Test Window"); - show_another_window ^= ImGui::Button("Another Window"); - // Calculate and show framerate - static float ms_per_frame[120] = { 0 }; - static int ms_per_frame_idx = 0; - static float ms_per_frame_accum = 0.0f; - ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx]; - ms_per_frame[ms_per_frame_idx] = ImGui::GetIO().DeltaTime * 1000.0f; - ms_per_frame_accum += ms_per_frame[ms_per_frame_idx]; - ms_per_frame_idx = (ms_per_frame_idx + 1) % 120; - const float ms_per_frame_avg = ms_per_frame_accum / 120; - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg); - - // Show the ImGui test window - // Most of user example code is in ImGui::ShowTestWindow() - if (show_test_window) + // 1. Show a simple window + // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug" { - ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly! - ImGui::ShowTestWindow(&show_test_window); + static float f; + ImGui::Text("Hello, world!"); + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); + show_test_window ^= ImGui::Button("Test Window"); + show_another_window ^= ImGui::Button("Another Window"); + + // Calculate and show framerate + static float ms_per_frame[120] = { 0 }; + static int ms_per_frame_idx = 0; + static float ms_per_frame_accum = 0.0f; + ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx]; + ms_per_frame[ms_per_frame_idx] = ImGui::GetIO().DeltaTime * 1000.0f; + ms_per_frame_accum += ms_per_frame[ms_per_frame_idx]; + ms_per_frame_idx = (ms_per_frame_idx + 1) % 120; + const float ms_per_frame_avg = ms_per_frame_accum / 120; + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg); } - // Show another simple window + // 2. Show another simple window, this time using an explicit Begin/End pair if (show_another_window) { ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100)); @@ -301,6 +305,13 @@ int main(int argc, char** argv) ImGui::End(); } + // 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow() + if (show_test_window) + { + ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call this, because positions are saved in .ini file. Here we just want to make the demo initial state a bit more friendly! + ImGui::ShowTestWindow(&show_test_window); + } + // Rendering glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); glClearColor(0.8f, 0.6f, 0.6f, 1.0f); diff --git a/imgui.cpp b/imgui.cpp index 7dd49f340..7c05d8fc6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// ImGui library v1.13 +// ImGui library v1.14 wip // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' below for notes on how to setup ImGui in your codebase. // Get latest version at https://github.com/ocornut/imgui @@ -185,11 +185,13 @@ - filters: set a current filter that tree node can automatically query to hide themselves - filters: handle wildcards (with implicit leading/trailing *), regexps - shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus) - - input: keyboard: full keyboard navigation and focus. + ! keyboard: tooltip & combo boxes are messing up / not honoring keyboard tabbing + - keyboard: full keyboard navigation and focus. - input: support trackpad style scrolling & slider edit. + - tooltip: move to fit within screen (e.g. when mouse cursor is right of the screen). - misc: not thread-safe - misc: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon? - - style editor: add a button to print C code. + - style editor: add a button to output C code. - optimisation/render: use indexed rendering - optimisation/render: move clip-rect to vertex data? would allow merging all commands - optimisation/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)? @@ -760,13 +762,16 @@ struct ImGuiWindow float ItemWidthDefault; ImGuiStorage StateStorage; float FontWindowScale; // Scale multipler per-window - - int FocusIdxCounter; // Start at -1 and increase as assigned via FocusItemRegister() - int FocusIdxRequestCurrent; // Item being requested for focus, rely on layout to be stable between the frame pressing TAB and the next frame - int FocusIdxRequestNext; // Item being requested for focus, for next update - ImDrawList* DrawList; + // Focus + int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister() + int FocusIdxTabCounter; // (same, but only count widgets which you can Tab through) + int FocusIdxAllRequestCurrent; // Item being requested for focus + int FocusIdxTabRequestCurrent; // Tab-able item being requested for focus + int FocusIdxAllRequestNext; // Item being requested for focus, for next update (relies on layout to be stable between the frame pressing TAB and the next frame) + int FocusIdxTabRequestNext; // " + public: ImGuiWindow(const char* name, ImVec2 default_pos, ImVec2 default_size); ~ImGuiWindow(); @@ -775,7 +780,7 @@ public: ImGuiID GetID(const void* ptr); void AddToRenderList(); - bool FocusItemRegister(bool is_active, int* out_idx = NULL); // Return TRUE if focus is requested + bool FocusItemRegister(bool is_active); // Return true if focus is requested void FocusItemUnregister(); ImGuiAabb Aabb() const { return ImGuiAabb(Pos, Pos+Size); } @@ -1017,12 +1022,12 @@ ImGuiWindow::ImGuiWindow(const char* name, ImVec2 default_pos, ImVec2 default_si if (ImLength(Size) < 0.001f) AutoFitFrames = 3; - FocusIdxCounter = -1; - FocusIdxRequestCurrent = IM_INT_MAX; - FocusIdxRequestNext = IM_INT_MAX; - DrawList = (ImDrawList*)ImGui::MemAlloc(sizeof(ImDrawList)); new(DrawList) ImDrawList(); + + FocusIdxAllCounter = FocusIdxTabCounter = -1; + FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = IM_INT_MAX; + FocusIdxAllRequestNext = FocusIdxTabRequestNext = IM_INT_MAX; } ImGuiWindow::~ImGuiWindow() @@ -1050,31 +1055,38 @@ ImGuiID ImGuiWindow::GetID(const void* ptr) return id; } -bool ImGuiWindow::FocusItemRegister(bool is_active, int* out_idx) +bool ImGuiWindow::FocusItemRegister(bool is_active) { - FocusIdxCounter++; - if (out_idx) - *out_idx = FocusIdxCounter; - ImGuiState& g = GImGui; ImGuiWindow* window = GetCurrentWindow(); - if (!window->DC.AllowKeyboardFocus.back()) - return false; - // Process input at this point: TAB, Shift-TAB switch focus - if (FocusIdxRequestNext == IM_INT_MAX && is_active && ImGui::IsKeyPressedMap(ImGuiKey_Tab)) + const bool allow_keyboard_focus = window->DC.AllowKeyboardFocus.back(); + FocusIdxAllCounter++; + if (allow_keyboard_focus) + FocusIdxTabCounter++; + + // Process keyboard input at this point: TAB, Shift-TAB switch focus + // We can always TAB out of a widget that doesn't allow tabbing in. + if (FocusIdxAllRequestNext == IM_INT_MAX && FocusIdxTabRequestNext == IM_INT_MAX && is_active && ImGui::IsKeyPressedMap(ImGuiKey_Tab)) { // Modulo on index will be applied at the end of frame once we've got the total counter of items. - FocusIdxRequestNext = FocusIdxCounter + (g.IO.KeyShift ? -1 : +1); + FocusIdxTabRequestNext = FocusIdxTabCounter + (g.IO.KeyShift ? (allow_keyboard_focus ? -1 : 0) : +1); } - const bool focus_requested = (FocusIdxCounter == FocusIdxRequestCurrent); - return focus_requested; + if (FocusIdxAllCounter == FocusIdxAllRequestCurrent) + return true; + + if (allow_keyboard_focus) + if (FocusIdxTabCounter == FocusIdxTabRequestCurrent) + return true; + + return false; } void ImGuiWindow::FocusItemUnregister() { - FocusIdxCounter--; + FocusIdxAllCounter--; + FocusIdxTabCounter--; } void ImGuiWindow::AddToRenderList() @@ -1387,7 +1399,7 @@ void NewFrame() // NB: Don't discard FocusedWindow if it isn't active, so that a window that go on/off programatically won't lose its keyboard focus. if (g.ActiveId == 0 && g.FocusedWindow != NULL && g.FocusedWindow->Visible && IsKeyPressedMap(ImGuiKey_Tab, false)) { - g.FocusedWindow->FocusIdxRequestNext = 0; + g.FocusedWindow->FocusIdxTabRequestNext = 0; } // Mark all windows as not visible @@ -2094,18 +2106,17 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin else window->ItemWidthDefault = 200.0f; - // Prepare for keyboard focus requests - if (window->FocusIdxRequestNext == IM_INT_MAX || window->FocusIdxCounter == -1) - { - window->FocusIdxRequestCurrent = IM_INT_MAX; - } + // Prepare for focus requests + if (window->FocusIdxAllRequestNext == IM_INT_MAX || window->FocusIdxAllCounter == -1) + window->FocusIdxAllRequestCurrent = IM_INT_MAX; else - { - const int mod = window->FocusIdxCounter+1; - window->FocusIdxRequestCurrent = (window->FocusIdxRequestNext + mod) % mod; - } - window->FocusIdxCounter = -1; - window->FocusIdxRequestNext = IM_INT_MAX; + window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1); + if (window->FocusIdxTabRequestNext == IM_INT_MAX || window->FocusIdxTabCounter == -1) + window->FocusIdxTabRequestCurrent = IM_INT_MAX; + else + window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1); + window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1; + window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX; ImGuiAabb title_bar_aabb = window->TitleBarAabb(); @@ -2627,6 +2638,13 @@ void SetScrollPosHere() window->NextScrollY = (window->DC.CursorPos.y + window->ScrollY) - (window->Pos.y + window->SizeFull.y * 0.5f) - (window->TitleBarHeight() + window->WindowPadding().y); } +void SetKeyboardFocusHere(int offset) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->FocusIdxAllRequestNext = window->FocusIdxAllCounter + 1 + offset; + window->FocusIdxTabRequestNext = IM_INT_MAX; +} + void SetTreeStateStorage(ImGuiStorage* tree) { ImGuiWindow* window = GetCurrentWindow(); @@ -6021,9 +6039,6 @@ void ShowTestWindow(bool* open) ImGui::Text("Thanks for clicking me!"); } - static bool check = true; - ImGui::Checkbox("checkbox", &check); - if (ImGui::TreeNode("Tree")) { for (size_t i = 0; i < 5; i++) @@ -6071,6 +6086,8 @@ void ShowTestWindow(bool* open) ImGui::TreePop(); } + static bool check = true; + ImGui::Checkbox("checkbox", &check); static int e = 0; ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); @@ -6374,6 +6391,41 @@ void ShowTestWindow(bool* open) ImGui::BulletText("%s", lines[i]); } + if (ImGui::CollapsingHeader("Keyboard & Focus")) + { + if (ImGui::TreeNode("Tabbing")) + { + ImGui::Text("Use TAB/SHIFT+TAB to cycle thru keyboard editable fields."); + static char buf[32] = "dummy"; + ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); + ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); + ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); + ImGui::PushAllowKeyboardFocus(false); + ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); + //ImGui::SameLine(); ImGui::Text("(?)"); if (ImGui::IsHovered()) ImGui::SetTooltip("Use ImGui::PushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets."); + ImGui::PopAllowKeyboardFocus(); + ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Focus from code")) + { + bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); + bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); + bool focus_3 = ImGui::Button("Focus on 3"); + static char buf[128] = "click on a button to set focus"; + if (focus_1) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); + if (focus_2) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); + ImGui::PushAllowKeyboardFocus(false); + if (focus_3) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); + ImGui::PopAllowKeyboardFocus(); + ImGui::TreePop(); + } + } + if (ImGui::CollapsingHeader("Long text")) { static ImGuiTextBuffer log; diff --git a/imgui.h b/imgui.h index 5e701ed64..576a8693c 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// ImGui library v1.13 +// ImGui library v1.14 wip // See .cpp file for commentary. // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase. @@ -153,12 +153,13 @@ namespace ImGui ImDrawList* GetWindowDrawList(); // get rendering command-list if you want to append your own draw primitives. void SetWindowFontScale(float scale); // per-window font scale. Adjust IO.FontBaseScale if you want to scale all windows together. void SetScrollPosHere(); // adjust scrolling position to center into the current cursor position. + void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use 'offset' to access sub components of a multiple component widget. void SetTreeStateStorage(ImGuiStorage* tree); // replace tree state storage with our own (if you want to manipulate it yourself, typically clear subsection of it). ImGuiStorage* GetTreeStateStorage(); void PushItemWidth(float item_width); void PopItemWidth(); float GetItemWidth(); - void PushAllowKeyboardFocus(bool v); + void PushAllowKeyboardFocus(bool v); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets. void PopAllowKeyboardFocus(); void PushStyleColor(ImGuiCol idx, const ImVec4& col); void PopStyleColor(); @@ -419,7 +420,7 @@ struct ImGuiIO ImVec2 FontTexUvForWhite; // = (0.0f,0.0f) // Font texture must have a white pixel at this UV coordinate. Adjust if you are using custom texture. float FontBaseScale; // = 1.0f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale() bool FontAllowUserScaling; // = false // Set to allow scaling text with CTRL+Wheel. - ImWchar FontFallbackGlyph; // = '?' // Replacement glyph is one isn't found. + ImWchar FontFallbackGlyph; // = '?' // Replacement glyph is one isn't found. float PixelCenterOffset; // = 0.0f // Try to set to 0.5f or 0.375f if rendering is blurry //------------------------------------------------------------------