diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 23abe87f..ac332415 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -13,12 +13,12 @@ You may use the Issue Tracker to submit bug reports, feature requests or suggest - If you get a assert, use a debugger to locate the line triggering it and read the comments around the assert. **Guidelines to report an issue or ask a question:** -- Try to provide a Minimal, Complete and Verifiable Example ([MCVE](https://stackoverflow.com/help/mcve)) to demonstrate your problem. An ideal submission includes a small piece of code that anyone can paste in one of the examples/ application to understand and reproduce it. Narrowing your problem to its shortest and purest form is often the easiest way to understand it. Often while creating the MCVE you will end up solving the problem! -- Try to attach screenshots to clarify the context. They often convey useful information that are omitted by the description. You can drag pictures/files here (prefer github attachments over 3rd party hosting). -- If you are discussing an assert or a crash, please provide a debugger callstack. - Please provide your imgui version number. +- If you are discussing an assert or a crash, please provide a debugger callstack. - Please state if you have made substantial modifications to your copy of imgui. - When discussing issues related to rendering or inputs, please state which OS you are using, and if you are using a vanilla copy of one of the back end (imgui_impl_xxx files), or a modified one, or if you built your own. +- Try to provide a Minimal, Complete and Verifiable Example ([MCVE](https://stackoverflow.com/help/mcve)) to demonstrate your problem. An ideal submission includes a small piece of code that anyone can paste in one of the examples/ application to understand and reproduce it. Narrowing your problem to its shortest and purest form is often the easiest way to understand it. Often while creating the MCVE you will end up solving the problem! +- Try to attach screenshots to clarify the context. They often convey useful information that are omitted by the description. You can drag pictures/files here (prefer github attachments over 3rd party hosting). - When requesting a new feature, please describe the usage context (how you intend to use it, why you need it, etc.). - Due to frequent abuse of this service from a certain category of users, if your GitHub account is anonymous and was created five minutes ago please understand that your post will receive more scrutiny and less patience for incomplete questions. diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 9491ae27..2470895e 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -48,6 +48,10 @@ Other Changes: (IN PROGRESS, WILL ADD TO THIS LIST AS WE WORK ON 1.61) - Settings: Fixed saving an empty .ini file if CreateContext/DestroyContext are called without a single call to NewFrame(). (#1741) +- Window: Fixed default proportional item width lagging by one frame on resize. +- Window: Fixed popups/tooltips/menus not honoring style.DisplaySafeAreaPadding as well as it should have (part of menus displayed outside the safe area, etc.). +- MenuBar: Made BeginMainMenuBar() honor style.DisplaySafeAreaPadding so the text can be made visible on TV settings that don't display all pixels. (#1439) [@dougbinks] +- Style: Changed default style.DisplaySafeAreaPadding values from (4,4) to (3,3) so it is smaller than FramePadding and has no effect on main menu bar on a computer. (#1439) ----------------------------------------------------------------------- @@ -122,7 +126,7 @@ Other Changes: - See https://github.com/ocornut/imgui/issues/1599 for recommended gamepad mapping or download PNG/PSD at http://goo.gl/9LgVZW - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. Read imgui.cpp for more details. - To use Keyboard Navigation: - - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeyDown[] + io.KeyMap[] arrays. + - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. - Basic controls: arrows to navigate, Alt to enter menus, Space to activate item, Enter to edit text, Escape to cancel/close, Ctrl-Tab to focus windows, etc. - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag will be set. For more advanced uses, you may want to read from io.NavActive or io.NavVisible. Read imgui.cpp for more details. diff --git a/TODO.txt b/TODO.txt index fc42b21f..2ddd1cf9 100644 --- a/TODO.txt +++ b/TODO.txt @@ -172,6 +172,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - text: proper alignment options in imgui_internal.h - text wrapped: figure out better way to use TextWrapped() in an always auto-resize context (tooltip, etc.) (#249) - text: it's currently impossible to have a window title with "##". perhaps an official workaround would be nice. \ style inhibitor? non-visible ascii code to insert between #? + - text: provided a framed text helper, e.g. https://pastebin.com/1Laxy8bT - text link/url button: underlined. should api expose an ID or use text contents as ID? which colors enum to use? - tree node / optimization: avoid formatting when clipped. @@ -188,6 +189,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - stb: add defines to disable stb implementations !- style: better default styles. (#707) + - style: add a highlighted text color (for headers, etc.) - style: border types: out-screen, in-screen, etc. (#447) - style/optimization: store rounded corners in texture to use 1 quad per corner (filled and wireframe) to lower the cost of rounding. - style: add window shadow (fading away from the window. Paint-style calculation of vertices alpha after drawlist would be easier) @@ -222,6 +224,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - font: better vertical centering (based e.g on height of lowercase 'x'?). currently Roboto-Medium size 16 px isn't currently centered. (#1619) - font: free the Alpha buffer if user only requested RGBA. !- font: better CalcTextSizeA() API, at least for simple use cases. current one is horrible (perhaps have simple vs extended versions). + - font: a CalcTextHeight() helper could run faster than CalcTextSize().y - font: enforce monospace through ImFontConfig (for icons?) + create dual ImFont output from same input, reusing rasterized data but with different glyphs/AdvanceX - font: finish CustomRectRegister() to allow mapping unicode codepoint to custom texture data - font: PushFontSize API (#1018) @@ -262,8 +265,9 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - misc: idle refresh: expose cursor blink animation timer for backend to be able to lower framerate. - misc: make the ImGuiCond values linear (non-power-of-two). internal storage for ImGuiWindow can use integers to combine into flags (Why?) - misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL) - - misc: fix for compilation settings where stdcall isn't the default (e.g. vectorcall) (#1230) - misc: PushItemFlag(): add a flag to disable keyboard capture when used with mouse? (#1682) + - misc: use more size_t in public api? + - misc: ImVector: erase_unsorted() helper - web/emscriptem: refactor some examples to facilitate integration with emscripten main loop system. (#1713, #336) - web/emscriptem: tweak OpenGL renderers to support OpenGL ES. (#1713, #336) diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index cd628b71..b07f33f9 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -124,7 +124,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy) #endif - // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; diff --git a/examples/imgui_impl_marmalade.cpp b/examples/imgui_impl_marmalade.cpp index 1b6fd6ef..680c16e1 100644 --- a/examples/imgui_impl_marmalade.cpp +++ b/examples/imgui_impl_marmalade.cpp @@ -217,7 +217,7 @@ void ImGui_Marmalade_InvalidateDeviceObjects() bool ImGui_Marmalade_Init(bool install_callbacks) { ImGuiIO& io = ImGui::GetIO(); - io.KeyMap[ImGuiKey_Tab] = s3eKeyTab; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. + io.KeyMap[ImGuiKey_Tab] = s3eKeyTab; // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. io.KeyMap[ImGuiKey_LeftArrow] = s3eKeyLeft; io.KeyMap[ImGuiKey_RightArrow] = s3eKeyRight; io.KeyMap[ImGuiKey_UpArrow] = s3eKeyUp; diff --git a/examples/imgui_impl_sdl2.cpp b/examples/imgui_impl_sdl2.cpp index 09391004..a4c9f042 100644 --- a/examples/imgui_impl_sdl2.cpp +++ b/examples/imgui_impl_sdl2.cpp @@ -132,7 +132,7 @@ bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context) io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) #endif - // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB; io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT; io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT; diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 1849a2d6..82c8724f 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -53,7 +53,7 @@ bool ImGui_ImplWin32_Init(void* hwnd) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui_ImplWin32_InitPlatformInterface(); - // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime. + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. io.KeyMap[ImGuiKey_Tab] = VK_TAB; io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; diff --git a/imgui.cpp b/imgui.cpp index 846ae9d7..cc1d0420 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -142,7 +142,7 @@ // Load texture atlas (there is a default font so you don't need to care about choosing a font yet) unsigned char* pixels; int width, height; - io.Fonts->GetTexDataAsRGBA32(pixels, &width, &height); + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // TODO: At this points you've got the texture data and you need to upload that your your graphic system: MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA) // TODO: Store your texture pointer/identifier (whatever your engine uses) in 'io.Fonts->TexID'. This will be passed back to your via the renderer. @@ -236,7 +236,7 @@ to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. - Keyboard: - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. - NewFrame() will automatically fill io.NavInputs[] based on your io.KeyDown[] + io.KeyMap[] arrays. + NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag will be set. For more advanced uses, you may want to read from: - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. @@ -838,7 +838,7 @@ ImGuiStyle::ImGuiStyle() GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. DisplayWindowPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. - DisplaySafeAreaPadding = ImVec2(4,4); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. + DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU. AntiAliasedFill = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) @@ -4757,13 +4757,9 @@ void ImGui::LogText(const char* fmt, ...) va_list args; va_start(args, fmt); if (g.LogFile) - { vfprintf(g.LogFile, fmt, args); - } else - { g.LogClipboard->appendfv(fmt, args); - } va_end(args); } @@ -4839,8 +4835,7 @@ void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool text_display_end = text_end; } - const int text_len = (int)(text_display_end - text); - if (text_len > 0) + if (text != text_display_end) { window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); if (g.LogEnabled) @@ -4856,8 +4851,7 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end if (!text_end) text_end = text + strlen(text); // FIXME-OPT - const int text_len = (int)(text_end - text); - if (text_len > 0) + if (text != text_end) { window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width); if (g.LogEnabled) @@ -5119,12 +5113,11 @@ static ImGuiWindow* FindHoveredWindow() bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; // Clip ImRect rect_clipped(r_min, r_max); if (clip) - rect_clipped.ClipWith(window->ClipRect); + rect_clipped.ClipWith(g.CurrentWindow->ClipRect); // Expand for touch input const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); @@ -5147,7 +5140,7 @@ int ImGui::GetKeyIndex(ImGuiKey imgui_key) return GImGui->IO.KeyMap[imgui_key]; } -// Note that imgui doesn't know the semantic of each entry of io.KeyDown[]. Use your own indices/enums according to how your back-end/engine stored them into KeyDown[]! +// Note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]! bool ImGui::IsKeyDown(int user_key_index) { if (user_key_index < 0) return false; @@ -5845,7 +5838,7 @@ static ImRect FindScreenRectForWindow(ImGuiWindow* window) { ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding; ImRect r_screen(window->Viewport->GetRect()); - r_screen.Expand(ImVec2((window->Size.x - r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (window->Size.y - r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); + r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); return r_screen; } @@ -6066,7 +6059,7 @@ static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents) else { ImVec2 avail_size = window->ViewportOwned ? ImVec2(FLT_MAX, FLT_MAX) : window->Viewport->Size; - ImVec2 size_auto_fit = ImClamp(size_contents, style.WindowMinSize, ImMax(style.WindowMinSize, avail_size - g.Style.DisplaySafeAreaPadding)); + ImVec2 size_auto_fit = ImClamp(size_contents, style.WindowMinSize, ImMax(style.WindowMinSize, avail_size - g.Style.DisplaySafeAreaPadding * 2.0f)); // When the window cannot fit all contents (either because of constraints, either because screen is too small), // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. @@ -6585,6 +6578,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->WindowPadding = style.WindowPadding; if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f) window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); + window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x); + window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; // Collapse window by double-clicking on title bar // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing @@ -6680,7 +6675,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Clamp position so window stays visible within its viewport // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. ImRect viewport_rect = window->Viewport->GetRect(); - if (!window_pos_set_by_api && !(flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) && !window->ViewportOwned && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && !window->ViewportOwned && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) if (viewport_rect.GetWidth() > 0 && viewport_rect.GetHeight() > 0.0f) { ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); @@ -6700,12 +6695,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->Pos = ImFloor(window->PosFloat); - // Default item width. Make it proportional to window size if window manually resizes - if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) - window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f); - else - window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f); - // Prepare for focus requests window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1); window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1); @@ -6738,6 +6727,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) viewport_rect = window->Viewport->GetRect(); } + // Default item width. Make it proportional to window size if window manually resizes + if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) + window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f); + else + window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f); + // DRAWING // Setup draw list and outer clipping rectangle @@ -6877,7 +6872,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; window->DC.NavLayerActiveMaskNext = 0x00; window->DC.MenuBarAppending = false; - window->DC.MenuBarOffsetX = ImMax(window->WindowPadding.x, style.ItemSpacing.x); window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; window->DC.ChildWindows.resize(0); window->DC.LayoutType = ImGuiLayoutType_Vertical; @@ -6954,12 +6948,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.NavLayerCurrentMask >>= 1; window->DC.ItemFlags = item_flags_backup; - // Title text (FIXME: refactor text alignment facilities along with RenderText helpers) + // Title text (FIXME: refactor text alignment facilities along with RenderText helpers, this is too much code for what it does.) ImVec2 text_size = CalcTextSize(name, NULL, true); ImRect text_r = title_bar_rect; - float pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0 ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : style.FramePadding.x; - float pad_right = (p_open != NULL) ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : style.FramePadding.x; - if (style.WindowTitleAlign.x > 0.0f) pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x); + float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); + float pad_right = (p_open == NULL) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); + if (style.WindowTitleAlign.x > 0.0f) + pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x); text_r.Min.x += pad_left; text_r.Max.x -= pad_right; ImRect clip_rect = text_r; @@ -6982,7 +6977,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Inner rectangle // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame - // Note that if our window is collapsed we will end up with a null clipping rectangle which is the correct behavior. + // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. window->InnerRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize; window->InnerRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x - window->WindowBorderSize; @@ -6996,7 +6991,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize))); window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y); - // After Begin() we fill the last item / hovered data using the title bar data. Make that a standard behavior (to allow usage of context menus on title bar only, etc.). + // After Begin() we fill the last item / hovered data based on title bar data. It is a standard behavior (to allow creation of context menus on title bar only, etc.). window->DC.LastItemId = window->MoveId; window->DC.LastItemStatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0; window->DC.LastItemRect = title_bar_rect; @@ -7018,7 +7013,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) g.NextWindowData.Clear(); // Child window can be out of sight and have "negative" clip windows. - // Mark them as collapsed so commands are skipped earlier (we can't manually collapse because they have no title bar). + // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). if (flags & ImGuiWindowFlags_ChildWindow) { IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); @@ -11941,21 +11936,24 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, return false; } +// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. bool ImGui::BeginMainMenuBar() { ImGuiContext& g = *GImGui; + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); SetNextWindowPos(ImVec2(0.0f, 0.0f)); - SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.FontBaseSize + g.Style.FramePadding.y * 2.0f)); + SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y)); PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0,0)); - if (!Begin("##MainMenuBar", NULL, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_MenuBar) - || !BeginMenuBar()) + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; + bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar(); + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); + if (!is_open) { End(); PopStyleVar(2); return false; } - g.CurrentWindow->DC.MenuBarOffsetX += g.Style.DisplaySafeAreaPadding.x; return true; } @@ -11984,14 +11982,14 @@ bool ImGui::BeginMenuBar() BeginGroup(); // Save position PushID("##menubar"); - // We don't clip with regular window clipping rectangle as it is already set to the area below. However we clip with window full rect. - // We remove 1 worth of rounding to Max.x to that text in long menus don't tend to display over the lower-right rounded area, which looks particularly glitchy. + // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. + // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. ImRect bar_rect = window->MenuBarRect(); ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f)); clip_rect.ClipWith(window->WindowRectClipped); PushClipRect(clip_rect.Min, clip_rect.Max, false); - window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffsetX, bar_rect.Min.y);// + g.Style.FramePadding.y); + window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); window->DC.LayoutType = ImGuiLayoutType_Horizontal; window->DC.NavLayerCurrent++; window->DC.NavLayerCurrentMask <<= 1; @@ -12031,7 +12029,7 @@ void ImGui::EndMenuBar() IM_ASSERT(window->DC.MenuBarAppending); PopClipRect(); PopID(); - window->DC.MenuBarOffsetX = window->DC.CursorPos.x - window->MenuBarRect().Min.x; + window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. window->DC.GroupStack.back().AdvanceCursor = false; EndGroup(); window->DC.LayoutType = ImGuiLayoutType_Vertical; diff --git a/imgui.h b/imgui.h index 9b9a3d98..e3e5ab31 100644 --- a/imgui.h +++ b/imgui.h @@ -520,7 +520,7 @@ namespace ImGui // Inputs IMGUI_API int GetKeyIndex(ImGuiKey imgui_key); // map ImGuiKey_* values into user's key index. == io.KeyMap[key] - IMGUI_API bool IsKeyDown(int user_key_index); // is key being held. == io.KeysDown[user_key_index]. note that imgui doesn't know the semantic of each entry of io.KeyDown[]. Use your own indices/enums according to how your backend/engine stored them into KeyDown[]! + IMGUI_API bool IsKeyDown(int user_key_index); // is key being held. == io.KeysDown[user_key_index]. note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your backend/engine stored them into io.KeysDown[]! IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat = true); // was key pressed (went from !Down to Down). if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate IMGUI_API bool IsKeyReleased(int user_key_index); // was key released (went from Down to !Down).. IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate @@ -750,7 +750,7 @@ enum ImGuiKey_ }; // [BETA] Gamepad/Keyboard directional navigation -// Keyboard: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeyDown[] + io.KeyMap[] arrays. +// Keyboard: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. // Gamepad: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. Back-end: set ImGuiBackendFlags_HasGamepad and fill the io.NavInputs[] fields before calling NewFrame(). Note that io.NavInputs[] is cleared by EndFrame(). // Read instructions in imgui.cpp for more details. Download PNG/PSD at goo.gl/9LgVZW. enum ImGuiNavInput_ @@ -774,7 +774,7 @@ enum ImGuiNavInput_ ImGuiNavInput_TweakFast, // faster tweaks // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) // [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them. - // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeyDown[] instead of io.NavInputs[]. + // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[]. ImGuiNavInput_KeyMenu_, // toggle menu // = io.KeyAlt ImGuiNavInput_KeyLeft_, // move left // = Arrow keys ImGuiNavInput_KeyRight_, // move right @@ -787,7 +787,7 @@ enum ImGuiNavInput_ // Configuration flags stored in io.ConfigFlags. Set by user/application. enum ImGuiConfigFlags_ { - ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeyDown[]. + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeysDown[]. ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. This is mostly to instruct your imgui back-end to fill io.NavInputs[]. Back-end also needs to set ImGuiBackendFlags_HasGamepad. ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your binding, otherwise ImGui will react as if the mouse is jumping around back and forth. ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag with io.NavActive is set. @@ -1003,7 +1003,7 @@ struct ImGuiStyle float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered. ImVec2 DisplayWindowPadding; // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. - ImVec2 DisplaySafeAreaPadding; // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. + ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. bool AntiAliasedLines; // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU. bool AntiAliasedFill; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3111599e..8d637660 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2171,6 +2171,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::Text("Alignment"); ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content."); + ImGui::Text("Safe Area Padding"); ImGui::SameLine(); ShowHelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); + ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::TreePop(); } diff --git a/imgui_internal.h b/imgui_internal.h index 19e92475..f697b71a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -568,6 +568,7 @@ struct ImGuiNextWindowData void* SizeCallbackUserData; float BgAlphaVal; ImGuiID ViewportId; + ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it. ImGuiNextWindowData() { @@ -580,6 +581,7 @@ struct ImGuiNextWindowData SizeCallbackUserData = NULL; BgAlphaVal = FLT_MAX; ViewportId = 0; + MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); } void Clear() @@ -878,7 +880,7 @@ struct IMGUI_API ImGuiDrawContext int NavLayerActiveMask; // Which layer have been written to (result from previous frame) int NavLayerActiveMaskNext; // Which layer have been written to (buffer for current frame) bool MenuBarAppending; // FIXME: Remove this - float MenuBarOffsetX; + ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. ImVector ChildWindows; ImGuiStorage* StateStorage; ImGuiLayoutType LayoutType; @@ -916,7 +918,7 @@ struct IMGUI_API ImGuiDrawContext NavLayerCurrent = 0; NavLayerCurrentMask = 1 << 0; MenuBarAppending = false; - MenuBarOffsetX = 0.0f; + MenuBarOffset = ImVec2(0.0f, 0.0f); StateStorage = NULL; LayoutType = ParentLayoutType = ImGuiLayoutType_Vertical; ItemWidth = 0.0f; @@ -1031,7 +1033,7 @@ public: float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale * FontDpiScale; } float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; } ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } - float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; } + float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; } ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } }; diff --git a/misc/fonts/README.txt b/misc/fonts/README.txt index 70773fca..f7468f02 100644 --- a/misc/fonts/README.txt +++ b/misc/fonts/README.txt @@ -81,7 +81,7 @@ In this document: - Mind the fact that some graphics drivers have texture size limitation. - Set io.Fonts.TexDesiredWidth to specify a texture width to minimize texture height (see comment in ImFontAtlas::Build function). - Set io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight; to disable rounding the texture height to the next power of two. - - You may reduce oversampling, e.g. config.OversampleH = 2 or 1. + - You may reduce oversampling, e.g. config.OversampleH = 1, this will largely reduce your textue size. - Reduce glyphs ranges, consider calculating them based on your source data if this is possible. Combine two fonts into one: