diff --git a/imgui/src/imgui/imgui.cpp b/imgui/src/imgui/imgui.cpp index b3c42da..0e40133 100644 --- a/imgui/src/imgui/imgui.cpp +++ b/imgui/src/imgui/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.80 +// dear imgui, v1.81 // (main code and documentation) // Help: @@ -75,6 +75,7 @@ CODE // [SECTION] DRAG AND DROP // [SECTION] LOGGING/CAPTURING // [SECTION] SETTINGS +// [SECTION] VIEWPORTS // [SECTION] PLATFORM DEPENDENT HELPERS // [SECTION] METRICS/DEBUGGER WINDOW @@ -238,7 +239,7 @@ CODE // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID. MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) - io.Fonts->TexID = (void*)texture; + io.Fonts->SetTexID((void*)texture); // Application main loop while (true) @@ -309,10 +310,11 @@ CODE // We are using scissoring to clip some objects. All low-level graphics API should supports it. // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches // (some elements visible outside their bounds) but you can fix that once everything else works! - // - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize) - // In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize. - // However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github), - // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. + // - Clipping coordinates are provided in imgui coordinates space: + // - For a given viewport, draw_data->DisplayPos == viewport->Pos and draw_data->DisplaySize == viewport->Size + // - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainViewport()->Pos/Size instead of hardcoding those values. + // - In the interest of supporting multi-viewport applications (see 'docking' branch on github), + // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) ImVec2 pos = draw_data->DisplayPos; MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->ClipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos.y)); @@ -373,6 +375,12 @@ CODE When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete). + - removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete). + - renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete). + - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. + - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. + - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018): - ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit(). - ImGuiCol_ModalWindowDarkening -> use ImGuiCol_ModalWindowDimBg @@ -616,9 +624,9 @@ CODE - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. - old: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..]; - - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->TexId = YourTexIdentifier; + - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->SetTexID(YourTexIdentifier); you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation. - - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. + - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to call io.Fonts->SetTexID() - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) @@ -846,8 +854,6 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* wind static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list); static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window); -static ImRect GetViewportRect(); - // Settings static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*); static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); @@ -894,6 +900,9 @@ static void RenderWindowOuterBorders(ImGuiWindow* window); static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); +// Viewports +static void UpdateViewportsNewFrame(); + } //----------------------------------------------------------------------------- @@ -1130,7 +1139,7 @@ void ImGuiIO::ClearInputCharacters() ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments) { - IM_ASSERT(num_segments > 0); // Use ImBezierClosestPointCasteljau() + IM_ASSERT(num_segments > 0); // Use ImBezierCubicClosestPointCasteljau() ImVec2 p_last = p1; ImVec2 p_closest; float p_closest_dist2 = FLT_MAX; @@ -3346,11 +3355,23 @@ void ImGui::DestroyContext(ImGuiContext* ctx) } // No specific ordering/dependency support, will see as needed -void ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook) +ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook) { ImGuiContext& g = *ctx; - IM_ASSERT(hook->Callback != NULL); + IM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_); g.Hooks.push_back(*hook); + g.Hooks.back().HookId = ++g.HookIdNext; + return g.HookIdNext; +} + +// Deferred removal, avoiding issue with changing vector while iterating it +void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id) +{ + ImGuiContext& g = *ctx; + IM_ASSERT(hook_id != 0); + for (int n = 0; n < g.Hooks.Size; n++) + if (g.Hooks[n].HookId == hook_id) + g.Hooks[n].Type = ImGuiContextHookType_PendingRemoval_; } // Call context hooks (used by e.g. test engine) @@ -3373,7 +3394,8 @@ ImGuiIO& ImGui::GetIO() ImDrawData* ImGui::GetDrawData() { ImGuiContext& g = *GImGui; - return g.DrawData.Valid ? &g.DrawData : NULL; + ImGuiViewportP* viewport = g.Viewports[0]; + return viewport->DrawDataP.Valid ? &viewport->DrawDataP : NULL; } double ImGui::GetTime() @@ -3386,14 +3408,50 @@ int ImGui::GetFrameCount() return GImGui->FrameCount; } +static ImDrawList* GetViewportDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name) +{ + // Create the draw list on demand, because they are not frequently used for all viewports + ImGuiContext& g = *GImGui; + IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->DrawLists)); + ImDrawList* draw_list = viewport->DrawLists[drawlist_no]; + if (draw_list == NULL) + { + draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData); + draw_list->_OwnerName = drawlist_name; + viewport->DrawLists[drawlist_no] = draw_list; + } + + // Our ImDrawList system requires that there is always a command + if (viewport->DrawListsLastFrame[drawlist_no] != g.FrameCount) + { + draw_list->_ResetForNewFrame(); + draw_list->PushTextureID(g.IO.Fonts->TexID); + draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false); + viewport->DrawListsLastFrame[drawlist_no] = g.FrameCount; + } + return draw_list; +} + +ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport) +{ + return GetViewportDrawList((ImGuiViewportP*)viewport, 0, "##Background"); +} + ImDrawList* ImGui::GetBackgroundDrawList() { - return &GImGui->BackgroundDrawList; + ImGuiContext& g = *GImGui; + return GetBackgroundDrawList(g.Viewports[0]); +} + +ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport) +{ + return GetViewportDrawList((ImGuiViewportP*)viewport, 1, "##Foreground"); } ImDrawList* ImGui::GetForegroundDrawList() { - return &GImGui->ForegroundDrawList; + ImGuiContext& g = *GImGui; + return GetForegroundDrawList(g.Viewports[0]); } ImDrawListSharedData* ImGui::GetDrawListSharedData() @@ -3475,7 +3533,8 @@ void ImGui::UpdateMouseMovingWindowEndFrame() if (g.NavWindow && g.NavWindow->Appearing) return; - // Click on empty space to focus window and start moving (after we're done with all our widgets) + // Click on empty space to focus window and start moving + // (after we're done with all our widgets) if (g.IO.MouseClicked[0]) { // Handle the edge case of a popup being closed while clicking in its empty space. @@ -3780,6 +3839,12 @@ void ImGui::NewFrame() { IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); ImGuiContext& g = *GImGui; + + // Remove pending delete hooks before frame start. + // This deferred removal avoid issues of removal while iterating the hook vector + for (int n = g.Hooks.Size - 1; n >= 0; n--) + if (g.Hooks[n].Type == ImGuiContextHookType_PendingRemoval_) + g.Hooks.erase(&g.Hooks[n]); CallContextHooks(&g, ImGuiContextHookType_NewFramePre); @@ -3802,11 +3867,16 @@ void ImGui::NewFrame() g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; + UpdateViewportsNewFrame(); + // Setup current font and draw list shared data g.IO.Fonts->Locked = true; SetCurrentFont(GetDefaultFont()); IM_ASSERT(g.Font->IsLoaded()); - g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); + ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + for (int n = 0; n < g.Viewports.Size; n++) + virtual_space.Add(g.Viewports[n]->GetMainRect()); + g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4(); g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; g.DrawListSharedData.SetCircleSegmentMaxError(g.Style.CircleSegmentMaxError); g.DrawListSharedData.InitialFlags = ImDrawListFlags_None; @@ -3819,16 +3889,12 @@ void ImGui::NewFrame() if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset; - g.BackgroundDrawList._ResetForNewFrame(); - g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID); - g.BackgroundDrawList.PushClipRectFullScreen(); - - g.ForegroundDrawList._ResetForNewFrame(); - g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID); - g.ForegroundDrawList.PushClipRectFullScreen(); - // Mark rendering data as invalid to prevent user who may have a handle on it to use it. - g.DrawData.Clear(); + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataP.Clear(); + } // Drag and drop keep the source ID alive so even if the source disappear our state is consistent if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) @@ -4015,6 +4081,10 @@ void ImGui::Initialize(ImGuiContext* context) TableSettingsInstallHandler(context); #endif // #ifdef IMGUI_HAS_TABLE + // Create default viewport + ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(); + g.Viewports.push_back(viewport); + #ifdef IMGUI_HAS_DOCK #endif // #ifdef IMGUI_HAS_DOCK @@ -4066,9 +4136,10 @@ void ImGui::Shutdown(ImGuiContext* context) g.FontStack.clear(); g.OpenPopupStack.clear(); g.BeginPopupStack.clear(); - g.DrawDataBuilder.ClearFreeMemory(); - g.BackgroundDrawList._ClearFreeMemory(); - g.ForegroundDrawList._ClearFreeMemory(); + + for (int i = 0; i < g.Viewports.Size; i++) + IM_DELETE(g.Viewports[i]); + g.Viewports.clear(); g.TabBars.Clear(); g.CurrentTabBarStack.clear(); @@ -4163,25 +4234,25 @@ static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* d out_list->push_back(draw_list); } -static void AddWindowToDrawData(ImVector* out_render_list, ImGuiWindow* window) +static void AddWindowToDrawData(ImGuiWindow* window, int layer) { ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = g.Viewports[0]; g.IO.MetricsRenderWindows++; - AddDrawListToDrawData(out_render_list, window->DrawList); + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[layer], window->DrawList); for (int i = 0; i < window->DC.ChildWindows.Size; i++) { ImGuiWindow* child = window->DC.ChildWindows[i]; - if (IsWindowActiveAndVisible(child)) // clipped children may have been marked not active - AddWindowToDrawData(out_render_list, child); + if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active + AddWindowToDrawData(child, layer); } } // Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu) static void AddRootWindowToDrawData(ImGuiWindow* window) { - ImGuiContext& g = *GImGui; int layer = (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0; - AddWindowToDrawData(&g.DrawDataBuilder.Layers[layer], window); + AddWindowToDrawData(window, layer); } void ImDrawDataBuilder::FlattenIntoSingleLayer() @@ -4202,15 +4273,16 @@ void ImDrawDataBuilder::FlattenIntoSingleLayer() } } -static void SetupDrawData(ImVector* draw_lists, ImDrawData* draw_data) +static void SetupViewportDrawData(ImGuiViewportP* viewport, ImVector* draw_lists) { ImGuiIO& io = ImGui::GetIO(); + ImDrawData* draw_data = &viewport->DrawDataP; draw_data->Valid = true; draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL; draw_data->CmdListsCount = draw_lists->Size; draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0; - draw_data->DisplayPos = ImVec2(0.0f, 0.0f); - draw_data->DisplaySize = io.DisplaySize; + draw_data->DisplayPos = viewport->Pos; + draw_data->DisplaySize = viewport->Size; draw_data->FramebufferScale = io.DisplayFramebufferScale; for (int n = 0; n < draw_lists->Size; n++) { @@ -4331,13 +4403,17 @@ void ImGui::Render() EndFrame(); g.FrameCountRendered = g.FrameCount; g.IO.MetricsRenderWindows = 0; - g.DrawDataBuilder.Clear(); CallContextHooks(&g, ImGuiContextHookType_RenderPre); - // Add background ImDrawList - if (!g.BackgroundDrawList.VtxBuffer.empty()) - AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.BackgroundDrawList); + // Add background ImDrawList (for each active viewport) + for (int n = 0; n != g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataBuilder.Clear(); + if (viewport->DrawLists[0] != NULL) + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); + } // Add ImDrawList to render ImGuiWindow* windows_to_render_top_most[2]; @@ -4352,20 +4428,27 @@ void ImGui::Render() for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++) if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window AddRootWindowToDrawData(windows_to_render_top_most[n]); - g.DrawDataBuilder.FlattenIntoSingleLayer(); - // Draw software mouse cursor if requested - if (g.IO.MouseDrawCursor) - RenderMouseCursor(&g.ForegroundDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)); + // Setup ImDrawData structures for end-user + g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0; + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataBuilder.FlattenIntoSingleLayer(); + + // Draw software mouse cursor if requested by io.MouseDrawCursor flag + if (g.IO.MouseDrawCursor) + RenderMouseCursor(GetForegroundDrawList(viewport), g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)); - // Add foreground ImDrawList - if (!g.ForegroundDrawList.VtxBuffer.empty()) - AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.ForegroundDrawList); + // Add foreground ImDrawList (for each active viewport) + if (viewport->DrawLists[1] != NULL) + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport)); - // Setup ImDrawData structure for end-user - SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData); - g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount; - g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount; + SetupViewportDrawData(viewport, &viewport->DrawDataBuilder.Layers[0]); + ImDrawData* draw_data = &viewport->DrawDataP; + g.IO.MetricsRenderVertices += draw_data->TotalVtxCount; + g.IO.MetricsRenderIndices += draw_data->TotalIdxCount; + } CallContextHooks(&g, ImGuiContextHookType_RenderPost); } @@ -4389,7 +4472,11 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); // Round - text_size.x = IM_FLOOR(text_size.x + 0.95f); + // FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out. + // FIXME: Investigate using ceilf or e.g. + // - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c + // - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html + text_size.x = IM_FLOOR(text_size.x + 0.99999f); return text_size; } @@ -4810,12 +4897,6 @@ ImVec2 ImGui::GetItemRectSize() return window->DC.LastItemRect.GetSize(); } -static ImRect GetViewportRect() -{ - ImGuiContext& g = *GImGui; - return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); -} - bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags) { ImGuiContext& g = *GImGui; @@ -4919,6 +5000,7 @@ void ImGui::EndChild() } } g.WithinEndChild = false; + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return } // Helper to create a child window / scrolling region that looks like a normal widget frame. @@ -4979,7 +5061,8 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) g.WindowsById.SetVoidPtr(window->ID, window); // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. - window->Pos = ImVec2(60, 60); + const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + window->Pos = main_viewport->Pos + ImVec2(60, 60); // User can disable loading and saving of settings. Tooltip and child windows also don't store settings. if (!(flags & ImGuiWindowFlags_NoSavedSettings)) @@ -5087,7 +5170,10 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont ImVec2 size_min = style.WindowMinSize; if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups) size_min = ImMin(size_min, ImVec2(4.0f, 4.0f)); - ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f)); + + // FIXME-VIEWPORT-WORKAREA: May want to use GetWorkSize() instead of Size depending on the type of windows? + ImVec2 avail_size = ImGui::GetMainViewport()->Size; + ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, avail_size - 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. @@ -5493,7 +5579,7 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button, - // while uncentered title text will still reach edges correct. + // while uncentered title text will still reach edges correctly. if (pad_l > style.FramePadding.x) pad_l += g.Style.ItemInnerSpacing.x; if (pad_r > style.FramePadding.x) @@ -5507,8 +5593,9 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl } ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y); - ImRect clip_r(layout_r.Min.x, layout_r.Min.y, layout_r.Max.x + g.Style.ItemInnerSpacing.x, layout_r.Max.y); - //if (g.IO.KeyCtrl) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] + ImRect clip_r(layout_r.Min.x, layout_r.Min.y, ImMin(layout_r.Max.x + g.Style.ItemInnerSpacing.x, title_bar_rect.Max.x), layout_r.Max.y); + //if (g.IO.KeyShift) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] + //if (g.IO.KeyCtrl) window->DrawList->AddRect(clip_r.Min, clip_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r); if (flags & ImGuiWindowFlags_UnsavedDocument) { @@ -5847,9 +5934,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Calculate the range of allowed position for that window (to be movable and visible past safe area padding) // When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect. - ImRect viewport_rect(GetViewportRect()); + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); + ImRect viewport_rect(viewport->GetMainRect()); + ImRect viewport_work_rect(viewport->GetWorkRect()); ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); - ImRect visibility_rect(viewport_rect.Min + visibility_padding, viewport_rect.Max - visibility_padding); + ImRect visibility_rect(viewport_work_rect.Min + visibility_padding, viewport_work_rect.Max - visibility_padding); // Clamp position/size so window stays visible within its viewport or monitor // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. @@ -6100,7 +6189,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) - RenderWindowTitleBarContents(window, title_bar_rect, name, p_open); + RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), name, p_open); // Clear hit test shape every frame window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0; @@ -6406,15 +6495,15 @@ void ImGui::PopButtonRepeat() void ImGui::PushTextWrapPos(float wrap_pos_x) { ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPosStack.push_back(window->DC.TextWrapPos); window->DC.TextWrapPos = wrap_pos_x; - window->DC.TextWrapPosStack.push_back(wrap_pos_x); } void ImGui::PopTextWrapPos() { ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPos = window->DC.TextWrapPosStack.back(); window->DC.TextWrapPosStack.pop_back(); - window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back(); } bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent) @@ -6549,6 +6638,7 @@ void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) ImVec2 offset = window->Pos - old_pos; window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected. + window->DC.IdealMaxPos += offset; window->DC.CursorStartPos += offset; } @@ -7371,12 +7461,13 @@ void ImGui::SetNextItemWidth(float item_width) g.NextItemData.Width = item_width; } +// FIXME: Remove the == 0.0f behavior? void ImGui::PushItemWidth(float item_width) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); - window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; } @@ -7387,18 +7478,19 @@ void ImGui::PushMultiItemsWidths(int components, float w_full) const ImGuiStyle& style = g.Style; const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components)); const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1))); + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width window->DC.ItemWidthStack.push_back(w_item_last); - for (int i = 0; i < components - 1; i++) + for (int i = 0; i < components - 2; i++) window->DC.ItemWidthStack.push_back(w_item_one); - window->DC.ItemWidth = window->DC.ItemWidthStack.back(); + window->DC.ItemWidth = (components == 1) ? w_item_last : w_item_one; g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; } void ImGui::PopItemWidth() { ImGuiWindow* window = GetCurrentWindow(); + window->DC.ItemWidth = window->DC.ItemWidthStack.back(); window->DC.ItemWidthStack.pop_back(); - window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back(); } // Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(). @@ -7544,7 +7636,7 @@ void ImGui::BeginGroup() window->DC.CursorMaxPos = window->DC.CursorPos; window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); if (g.LogEnabled) - g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return } void ImGui::EndGroup() @@ -7565,7 +7657,7 @@ void ImGui::EndGroup() window->DC.CurrLineSize = group_data.BackupCurrLineSize; window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset; if (g.LogEnabled) - g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return if (!group_data.EmitItem) { @@ -8130,7 +8222,10 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla // (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves) // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) - SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); + { + const ImGuiViewport* viewport = GetMainViewport(); + SetNextWindowPos(viewport->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); + } flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse; const bool is_open = Begin(name, p_open, flags); @@ -8223,6 +8318,9 @@ bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flag // r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.) // r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it. +// (r_outer is usually equivalent to the viewport rectangle minus padding, but when multi-viewports are enabled and monitor +// information are available, it may represent the entire platform monitor from the frame of reference of the current viewport. +// this allows us to have tooltips/popups displayed out of the parent viewport.) ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) { ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); @@ -8297,11 +8395,13 @@ ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& s return pos; } +// Note that this is used for popups, which can overlap the non work-area of individual viewports. ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window) { + ImGuiContext& g = *GImGui; IM_UNUSED(window); - ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding; - ImRect r_screen = GetViewportRect(); + ImRect r_screen = ((ImGuiViewportP*)(void*)GetMainViewport())->GetMainRect(); + ImVec2 padding = g.Style.DisplaySafeAreaPadding; 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; } @@ -8745,8 +8845,8 @@ static ImVec2 ImGui::NavCalcPreferredRefPos() // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item. const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer]; ImVec2 pos = g.NavWindow->Pos + ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight())); - ImRect visible_rect = GetViewportRect(); - return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); // ImFloor() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta. + ImGuiViewport* viewport = GetMainViewport(); + return ImFloor(ImClamp(pos, viewport->Pos, viewport->Pos + viewport->Size)); // ImFloor() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta. } } @@ -9049,7 +9149,7 @@ static void ImGui::NavUpdate() // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items) ImRect nav_rect_rel = g.NavWindow ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); - g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect(); + g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : ImRect(0, 0, 0, 0); g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y); g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x); g.NavScoringRect.Max.x = g.NavScoringRect.Min.x; @@ -9479,8 +9579,9 @@ void ImGui::NavUpdateWindowingOverlay() if (g.NavWindowingListWindow == NULL) g.NavWindowingListWindow = FindWindowByName("###NavWindowingList"); - SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); - SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + const ImGuiViewport* viewport = GetMainViewport(); + SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); + SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) @@ -9831,54 +9932,63 @@ void ImGui::LogText(const char* fmt, ...) // Internal version that takes a position to decide on newline placement and pad items according to their depth. // We split text into individual lines to add current tree level padding +// FIXME: This code is a little complicated perhaps, considering simplifying the whole system. void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + const char* prefix = g.LogNextPrefix; + const char* suffix = g.LogNextSuffix; + g.LogNextPrefix = g.LogNextSuffix = NULL; + if (!text_end) text_end = FindRenderedTextEnd(text, text_end); - const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + 1); + const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1); if (ref_pos) g.LogLinePosY = ref_pos->y; if (log_new_line) + { + LogText(IM_NEWLINE); g.LogLineFirstItem = true; + } - const char* text_remaining = text; - if (g.LogDepthRef > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth + if (prefix) + LogRenderedText(ref_pos, prefix, prefix + strlen(prefix)); // Calculate end ourself to ensure "##" are included here. + + // Re-adjust padding if we have popped out of our starting depth + if (g.LogDepthRef > window->DC.TreeDepth) g.LogDepthRef = window->DC.TreeDepth; const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef); + + const char* text_remaining = text; for (;;) { - // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry. - // We don't add a trailing \n to allow a subsequent item on the same line to be captured. + // Split the string. Each new line (after a '\n') is followed by indentation corresponding to the current depth of our log entry. + // We don't add a trailing \n yet to allow a subsequent item on the same line to be captured. const char* line_start = text_remaining; const char* line_end = ImStreolRange(line_start, text_end); - const bool is_first_line = (line_start == text); const bool is_last_line = (line_end == text_end); - if (!is_last_line || (line_start != line_end)) + if (line_start != line_end || !is_last_line) { - const int char_count = (int)(line_end - line_start); - if (log_new_line || !is_first_line) - LogText(IM_NEWLINE "%*s%.*s", tree_depth * 4, "", char_count, line_start); - else if (g.LogLineFirstItem) - LogText("%*s%.*s", tree_depth * 4, "", char_count, line_start); - else - LogText(" %.*s", char_count, line_start); + const int line_length = (int)(line_end - line_start); + const int indentation = g.LogLineFirstItem ? tree_depth * 4 : 1; + LogText("%*s%.*s", indentation, "", line_length, line_start); g.LogLineFirstItem = false; + if (*line_end == '\n') + { + LogText(IM_NEWLINE); + g.LogLineFirstItem = true; + } } - else if (log_new_line) - { - // An empty "" string at a different Y position should output a carriage return. - LogText(IM_NEWLINE); - break; - } - if (is_last_line) break; text_remaining = line_end + 1; } + + if (suffix) + LogRenderedText(ref_pos, suffix, suffix + strlen(suffix)); } // Start logging/capturing text output @@ -9891,12 +10001,21 @@ void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) IM_ASSERT(g.LogBuffer.empty()); g.LogEnabled = true; g.LogType = type; + g.LogNextPrefix = g.LogNextSuffix = NULL; g.LogDepthRef = window->DC.TreeDepth; g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); g.LogLinePosY = FLT_MAX; g.LogLineFirstItem = true; } +// Important: doesn't copy underlying data, use carefully (prefix/suffix must be in scope at the time of the next LogRenderedText) +void ImGui::LogSetNextTextDecoration(const char* prefix, const char* suffix) +{ + ImGuiContext& g = *GImGui; + g.LogNextPrefix = prefix; + g.LogNextSuffix = suffix; +} + void ImGui::LogToTTY(int auto_open_depth) { ImGuiContext& g = *GImGui; @@ -10327,9 +10446,41 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl //----------------------------------------------------------------------------- // [SECTION] VIEWPORTS, PLATFORM WINDOWS //----------------------------------------------------------------------------- +// - GetMainViewport() +// - UpdateViewportsNewFrame() [Internal] +// (this section is more complete in the 'docking' branch) +//----------------------------------------------------------------------------- -// (this section is filled in the 'docking' branch) +ImGuiViewport* ImGui::GetMainViewport() +{ + ImGuiContext& g = *GImGui; + return g.Viewports[0]; +} +// Update viewports and monitor infos +static void ImGui::UpdateViewportsNewFrame() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Viewports.Size == 1); + + // Update main viewport with current platform position. + // FIXME-VIEWPORT: Size is driven by backend/user code for backward-compatibility but we should aim to make this more consistent. + ImGuiViewportP* main_viewport = g.Viewports[0]; + main_viewport->Flags = ImGuiViewportFlags_IsPlatformWindow | ImGuiViewportFlags_OwnedByApp; + main_viewport->Pos = ImVec2(0.0f, 0.0f); + main_viewport->Size = g.IO.DisplaySize; + + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + + // Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again. + viewport->WorkOffsetMin = viewport->CurrWorkOffsetMin; + viewport->WorkOffsetMax = viewport->CurrWorkOffsetMax; + viewport->CurrWorkOffsetMin = viewport->CurrWorkOffsetMax = ImVec2(0.0f, 0.0f); + viewport->UpdateWorkRect(); + } +} //----------------------------------------------------------------------------- // [SECTION] DOCKING @@ -10501,6 +10652,8 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} //----------------------------------------------------------------------------- // [SECTION] METRICS/DEBUGGER WINDOW //----------------------------------------------------------------------------- +// - RenderViewportThumbnail() [Internal] +// - RenderViewportsThumbnails() [Internal] // - MetricsHelpMarker() [Internal] // - ShowMetricsWindow() // - DebugNodeColumns() [Internal] @@ -10508,6 +10661,7 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} // - DebugNodeDrawCmdShowMeshAndBoundingBox() [Internal] // - DebugNodeStorage() [Internal] // - DebugNodeTabBar() [Internal] +// - DebugNodeViewport() [Internal] // - DebugNodeWindow() [Internal] // - DebugNodeWindowSettings() [Internal] // - DebugNodeWindowsList() [Internal] @@ -10515,6 +10669,57 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} #ifndef IMGUI_DISABLE_METRICS_WINDOW +void ImGui::DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImVec2 scale = bb.GetSize() / viewport->Size; + ImVec2 off = bb.Min - viewport->Pos * scale; + float alpha_mul = 1.0f; + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f)); + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* thumb_window = g.Windows[i]; + if (!thumb_window->WasActive || (thumb_window->Flags & ImGuiWindowFlags_ChildWindow)) + continue; + + ImRect thumb_r = thumb_window->Rect(); + ImRect title_r = thumb_window->TitleBarRect(); + thumb_r = ImRect(ImFloor(off + thumb_r.Min * scale), ImFloor(off + thumb_r.Max * scale)); + title_r = ImRect(ImFloor(off + title_r.Min * scale), ImFloor(off + ImVec2(title_r.Max.x, title_r.Min.y) * scale) + ImVec2(0,5)); // Exaggerate title bar height + thumb_r.ClipWithFull(bb); + title_r.ClipWithFull(bb); + const bool window_is_focused = (g.NavWindow && thumb_window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight); + window->DrawList->AddRectFilled(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_WindowBg, alpha_mul)); + window->DrawList->AddRectFilled(title_r.Min, title_r.Max, GetColorU32(window_is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg, alpha_mul)); + window->DrawList->AddRect(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_Border, alpha_mul)); + window->DrawList->AddText(g.Font, g.FontSize * 1.0f, title_r.Min, GetColorU32(ImGuiCol_Text, alpha_mul), thumb_window->Name, FindRenderedTextEnd(thumb_window->Name)); + } + draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul)); +} + +static void RenderViewportsThumbnails() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // We don't display full monitor bounds (we could, but it often looks awkward), instead we display just enough to cover all of our viewports. + float SCALE = 1.0f / 8.0f; + ImRect bb_full(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + for (int n = 0; n < g.Viewports.Size; n++) + bb_full.Add(g.Viewports[n]->GetMainRect()); + ImVec2 p = window->DC.CursorPos; + ImVec2 off = p - bb_full.Min * SCALE; + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + ImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE); + ImGui::DebugRenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb); + } + ImGui::Dummy(bb_full.GetSize() * SCALE); +} + // Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. static void MetricsHelpMarker(const char* desc) { @@ -10542,7 +10747,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; // Basic info - Text("Dear ImGui %s", ImGui::GetVersion()); + Text("Dear ImGui %s", GetVersion()); Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows); @@ -10673,13 +10878,34 @@ void ImGui::ShowMetricsWindow(bool* p_open) TreePop(); } - // Contents + // Windows DebugNodeWindowsList(&g.Windows, "Windows"); - //DebugNodeWindowList(&g.WindowsFocusOrder, "WindowsFocusOrder"); - if (TreeNode("DrawLists", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size)) + //DebugNodeWindowsList(&g.WindowsFocusOrder, "WindowsFocusOrder"); + + // DrawLists + int drawlist_count = 0; + for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) + drawlist_count += g.Viewports[viewport_i]->DrawDataBuilder.GetDrawListCount(); + if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count)) { - for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++) - DebugNodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList"); + for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) + { + ImGuiViewportP* viewport = g.Viewports[viewport_i]; + for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++) + for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++) + DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList"); + } + TreePop(); + } + + // Viewports + if (TreeNode("Viewports", "Viewports (%d)", g.Viewports.Size)) + { + Indent(GetTreeNodeToLabelSpacing()); + RenderViewportsThumbnails(); + Unindent(GetTreeNodeToLabelSpacing()); + for (int i = 0; i < g.Viewports.Size; i++) + DebugNodeViewport(g.Viewports[i]); TreePop(); } @@ -10922,7 +11148,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); bool pcmd_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf); if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list) - DebugNodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes); + DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes); if (!pcmd_node_open) continue; @@ -10943,7 +11169,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area); Selectable(buf); if (IsItemHovered() && fg_draw_list) - DebugNodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, true, false); + DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, true, false); // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. ImGuiListClipper clipper; @@ -10976,33 +11202,32 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, } // [DEBUG] Display mesh/aabb of a ImDrawCmd -void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow* window, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb) +void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb) { IM_ASSERT(show_mesh || show_aabb); - ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset; // Draw wire-frame version of all triangles ImRect clip_rect = draw_cmd->ClipRect; ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); - ImDrawListFlags backup_flags = fg_draw_list->Flags; - fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + ImDrawListFlags backup_flags = out_draw_list->Flags; + out_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. for (unsigned int idx_n = draw_cmd->IdxOffset; idx_n < draw_cmd->IdxOffset + draw_cmd->ElemCount; ) { ImVec2 triangle[3]; for (int n = 0; n < 3; n++, idx_n++) vtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos)); if (show_mesh) - fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); // In yellow: mesh triangles + out_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); // In yellow: mesh triangles } // Draw bounding boxes if (show_aabb) { - fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU - fg_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles + out_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU + out_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles } - fg_draw_list->Flags = backup_flags; + out_draw_list->Flags = backup_flags; } // [DEBUG] Display contents of ImGuiStorage @@ -11054,6 +11279,26 @@ void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label) } } +void ImGui::DebugNodeViewport(ImGuiViewportP* viewport) +{ + SetNextItemOpen(true, ImGuiCond_Once); + if (TreeNode("viewport0", "Viewport #%d", 0)) + { + ImGuiWindowFlags flags = viewport->Flags; + BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f", + viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y, + viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y); + BulletText("Flags: 0x%04X =%s%s%s", viewport->Flags, + (flags & ImGuiViewportFlags_IsPlatformWindow) ? " IsPlatformWindow" : "", + (flags & ImGuiViewportFlags_IsPlatformMonitor) ? " IsPlatformMonitor" : "", + (flags & ImGuiViewportFlags_OwnedByApp) ? " OwnedByApp" : ""); + for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++) + for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++) + DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList"); + TreePop(); + } +} + void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) { if (window == NULL) @@ -11111,7 +11356,6 @@ void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings) settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed); } - void ImGui::DebugNodeWindowsList(ImVector* windows, const char* label) { if (!TreeNode(label, "%s (%d)", label, windows->Size)) @@ -11131,12 +11375,13 @@ void ImGui::DebugNodeWindowsList(ImVector* windows, const char* la void ImGui::ShowMetricsWindow(bool*) {} void ImGui::DebugNodeColumns(ImGuiOldColumns*) {} void ImGui::DebugNodeDrawList(ImGuiWindow*, const ImDrawList*, const char*) {} -void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} +void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {} void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {} void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {} void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {} void ImGui::DebugNodeWindowsList(ImVector*, const char*) {} +void ImGui::DebugNodeViewport(ImGuiViewportP*) {} #endif diff --git a/imgui/src/imgui/imgui.h b/imgui/src/imgui/imgui.h index 99f03de..408969a 100644 --- a/imgui/src/imgui/imgui.h +++ b/imgui/src/imgui/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.80 +// dear imgui, v1.81 // (headers) // Help: @@ -31,6 +31,7 @@ Index of this file: // [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) +// [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) */ @@ -58,8 +59,8 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) -#define IMGUI_VERSION "1.80" -#define IMGUI_VERSION_NUM 18000 +#define IMGUI_VERSION "1.81" +#define IMGUI_VERSION_NUM 18100 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_HAS_TABLE @@ -125,6 +126,7 @@ struct ImDrawListSplitter; // Helper to split a draw list into differen struct ImDrawVert; // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) struct ImFont; // Runtime data for a single font within a parent ImFontAtlas struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader +struct ImFontBuilderIO; // Opaque interface to a font builder (stb_truetype or FreeType). struct ImFontConfig; // Configuration data when adding a font or merging fonts struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data @@ -142,6 +144,7 @@ struct ImGuiTableSortSpecs; // Sorting specifications for a table (often struct ImGuiTableColumnSortSpecs; // Sorting specification for one column of a table struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder) struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]") +struct ImGuiViewport; // A Platform Window (always only one in 'master' branch), in the future may represent Platform Monitor // Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file) // - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! @@ -180,6 +183,7 @@ typedef int ImGuiTableFlags; // -> enum ImGuiTableFlags_ // Flags: F typedef int ImGuiTableColumnFlags; // -> enum ImGuiTableColumnFlags_// Flags: For TableSetupColumn() typedef int ImGuiTableRowFlags; // -> enum ImGuiTableRowFlags_ // Flags: For TableNextRow() typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader() +typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild() // Other types @@ -374,7 +378,7 @@ namespace ImGui IMGUI_API void PopButtonRepeat(); // Parameters stacks (current window) - IMGUI_API void PushItemWidth(float item_width); // push width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side). 0.0f = default to ~2/3 of windows width, + IMGUI_API void PushItemWidth(float item_width); // push width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side). IMGUI_API void PopItemWidth(); IMGUI_API void SetNextItemWidth(float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side) IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position. NOT necessarily the width of last item unlike most 'Item' functions. @@ -413,8 +417,8 @@ namespace ImGui IMGUI_API void SetCursorPosX(float local_x); // GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.) IMGUI_API void SetCursorPosY(float local_y); // IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position in window coordinates - IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates [0..io.DisplaySize] (useful to work with ImDrawList API) - IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates [0..io.DisplaySize] + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute coordinates (useful to work with ImDrawList API). generally top-left == GetMainViewport()->Pos == (0,0) in single viewport mode, and bottom-right == GetMainViewport()->Pos+Size == io.DisplaySize in single-viewport mode. + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute coordinates IMGUI_API void AlignTextToFramePadding(); // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item) IMGUI_API float GetTextLineHeight(); // ~ FontSize IMGUI_API float GetTextLineHeightWithSpacing(); // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text) @@ -471,7 +475,7 @@ namespace ImGui // Widgets: Combo Box // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. - // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. + // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. This is analogous to how ListBox are created. IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1); @@ -578,14 +582,18 @@ namespace ImGui IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. // Widgets: List Boxes - // - FIXME: To be consistent with all the newer API, ListBoxHeader/ListBoxFooter should in reality be called BeginListBox/EndListBox. Will rename them. + // - This is essentially a thin wrapper to using BeginChild/EndChild with some stylistic changes. + // - The BeginListBox()/EndListBox() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() or any items. + // - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analoguous to how Combos are created. + // - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth + // - Choose frame height: size.y > 0.0f: custom / size.y < 0.0f or -FLT_MIN: bottom-align / size.y = 0.0f (default): arbitrary default height which can fit ~7 items + IMGUI_API bool BeginListBox(const char* label, const ImVec2& size = ImVec2(0, 0)); // open a framed scrolling region + IMGUI_API void EndListBox(); // only call EndListBox() if BeginListBox() returned true! IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); - IMGUI_API bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)); // use if you want to reimplement ListBox() will custom data or interactions. if the function return true, you can output elements then call ListBoxFooter() afterwards. - IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // " - IMGUI_API void ListBoxFooter(); // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true! // Widgets: Data Plotting + // - Consider using ImPlot (https://github.com/epezent/implot) IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); @@ -782,6 +790,12 @@ namespace ImGui IMGUI_API ImVec2 GetItemRectSize(); // get size of last item IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area. + // Viewports + // - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. + // - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports. + // - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. + IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport. + // Miscellaneous Utilities IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side. @@ -1084,7 +1098,7 @@ enum ImGuiTableFlags_ ImGuiTableFlags_SizingFixedFit = 1 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching contents width. ImGuiTableFlags_SizingFixedSame = 2 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching the maximum contents width of all columns. Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible. ImGuiTableFlags_SizingStretchProp = 3 << 13, // Columns default to _WidthStretch with default weights proportional to each columns contents widths. - ImGuiTableFlags_SizingStretchSame = 4 << 13, // Columns default to _WidthStretch with default weights all equal, unless overriden by TableSetupColumn(). + ImGuiTableFlags_SizingStretchSame = 4 << 13, // Columns default to _WidthStretch with default weights all equal, unless overridden by TableSetupColumn(). // Sizing Extra Options ImGuiTableFlags_NoHostExtendX = 1 << 16, // Make outer width auto-fit to columns, overriding outer_size.x value. Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. ImGuiTableFlags_NoHostExtendY = 1 << 17, // Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible. @@ -1731,7 +1745,7 @@ struct ImGuiIO ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend. - ImVec2 DisplaySize; // // Main display size, in pixels. + ImVec2 DisplaySize; // // Main display size, in pixels (generally == GetMainViewport()->Size) float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. const char* IniFilename; // = "imgui.ini" // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory. @@ -1959,6 +1973,10 @@ struct ImGuiTableSortSpecs #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS namespace ImGui { + // OBSOLETED in 1.81 (from February 2021) + IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // Helper to calculate size from items_count and height_in_items + static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } + static inline void ListBoxFooter() { EndListBox(); } // OBSOLETED in 1.79 (from August 2020) static inline void OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry! // OBSOLETED in 1.78 (from June 2020) @@ -2325,7 +2343,8 @@ enum ImDrawListFlags_ // Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to // access the current window draw list and draw custom primitives. // You can interleave normal ImGui:: calls and adding primitives to the current draw list. -// All positions are generally in pixel coordinates (top-left at (0,0), bottom-right at io.DisplaySize), but you are totally free to apply whatever transformation matrix to want to the data (if you apply such transformation you'll want to apply it to ClipRect as well) +// In single viewport mode, top-left is == GetMainViewport()->Pos (generally 0,0), bottom-right is == GetMainViewport()->Pos+Size (generally io.DisplaySize). +// You are totally free to apply whatever transformation matrix to want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!) // Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. struct ImDrawList { @@ -2400,9 +2419,9 @@ struct ImDrawList inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order. inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; } IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 10); - IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle - IMGUI_API void PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); // Cubic Bezier (4 control points) - IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points) + IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle + IMGUI_API void PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); // Cubic Bezier (4 control points) + IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points) IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); // Advanced @@ -2452,18 +2471,17 @@ struct ImDrawList struct ImDrawData { bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. - ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. int CmdListsCount; // Number of ImDrawList* to render int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size - ImVec2 DisplayPos; // Upper-left position of the viewport to render (== upper-left of the orthogonal projection matrix to use) - ImVec2 DisplaySize; // Size of the viewport to render (== io.DisplaySize for the main viewport) (DisplayPos + DisplaySize == lower-right of the orthogonal projection matrix to use) + ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. + ImVec2 DisplayPos; // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport applications) + ImVec2 DisplaySize; // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications) ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. // Functions - ImDrawData() { Valid = false; Clear(); } - ~ImDrawData() { Clear(); } - void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.f, 0.f); } // The ImDrawList are owned by ImGuiContext! + ImDrawData() { Clear(); } + void Clear() { memset(this, 0, sizeof(*this)); } // The ImDrawList are owned by ImGuiContext! IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. }; @@ -2479,8 +2497,8 @@ struct ImFontConfig bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). int FontNo; // 0 // Index of font within TTF/OTF file float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). - int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. - int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. + int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal so you can reduce this to 2 to save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis. bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. @@ -2488,7 +2506,7 @@ struct ImFontConfig float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. - unsigned int RasterizerFlags; // 0x00 // Settings for custom font rasterizer (e.g. ImGuiFreeType). Leave as zero if you aren't using one. + unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. ImWchar EllipsisChar; // -1 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. @@ -2503,8 +2521,9 @@ struct ImFontConfig // (Note: some language parsers may fail to convert the 31+1 bitfield members, in this case maybe drop store a single u32 or we can rework this) struct ImFontGlyph { - unsigned int Codepoint : 31; // 0x0000..0xFFFF - unsigned int Visible : 1; // Flag to allow early out when rendering + unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops) + unsigned int Visible : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering. + unsigned int Codepoint : 30; // 0x0000..0x10FFFF float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) float X0, Y0, X1, Y1; // Glyph corners float U0, V0, U1, V1; // Texture coordinates @@ -2648,6 +2667,10 @@ struct ImFontAtlas ImVector ConfigData; // Configuration data ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines + // [Internal] Font builder + const ImFontBuilderIO* FontBuilderIO; // Opaque interface to a font builder (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). + unsigned int FontBuilderFlags; // Shared flags (for all fonts) for custom font builder. THIS IS BUILD IMPLEMENTATION DEPENDENT. Per-font override is also available in ImFontConfig. + // [Internal] Packing data int PackIdMouseCursors; // Custom texture rectangle ID for white pixel and mouse cursors int PackIdLines; // Custom texture rectangle ID for baked anti-aliased lines @@ -2711,6 +2734,43 @@ struct ImFont IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); }; +//----------------------------------------------------------------------------- +// [SECTION] Viewports +//----------------------------------------------------------------------------- + +// Flags stored in ImGuiViewport::Flags +enum ImGuiViewportFlags_ +{ + ImGuiViewportFlags_None = 0, + ImGuiViewportFlags_IsPlatformWindow = 1 << 0, // Represent a Platform Window + ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, // Represent a Platform Monitor (unused yet) + ImGuiViewportFlags_OwnedByApp = 1 << 2 // Platform Window: is created/managed by the application (rather than a dear imgui backend) +}; + +// - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. +// - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports. +// - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. +// - About Main Area vs Work Area: +// - Main Area = entire viewport. +// - Work Area = entire viewport minus sections used by main menu bars (for platform windows), or by task bar (for platform monitor). +// - Windows are generally trying to stay within the Work Area of their host viewport. +struct ImGuiViewport +{ + ImGuiViewportFlags Flags; // See ImGuiViewportFlags_ + ImVec2 Pos; // Main Area: Position of the viewport (Dear Imgui coordinates are the same as OS desktop/native coordinates) + ImVec2 Size; // Main Area: Size of the viewport. + ImVec2 WorkPos; // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos) + ImVec2 WorkSize; // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) + + ImGuiViewport() { memset(this, 0, sizeof(*this)); } + + // Helpers + ImVec2 GetCenter() const { return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); } + ImVec2 GetWorkCenter() const { return ImVec2(WorkPos.x + WorkSize.x * 0.5f, WorkPos.y + WorkSize.y * 0.5f); } +}; + +//----------------------------------------------------------------------------- + #if defined(__clang__) #pragma clang diagnostic pop #elif defined(__GNUC__) diff --git a/imgui/src/imgui/imgui_demo.cpp b/imgui/src/imgui/imgui_demo.cpp index a19d4a0..90e91aa 100644 --- a/imgui/src/imgui/imgui_demo.cpp +++ b/imgui/src/imgui/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.80 +// dear imgui, v1.81 // (demo code) // Help: @@ -63,8 +63,9 @@ Index of this file: // [SECTION] Example App: Long Text / ShowExampleAppLongText() // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() -// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() -// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() +// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() +// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() @@ -168,6 +169,7 @@ static void ShowExampleAppLongText(bool* p_open); static void ShowExampleAppAutoResize(bool* p_open); static void ShowExampleAppConstrainedResize(bool* p_open); static void ShowExampleAppSimpleOverlay(bool* p_open); +static void ShowExampleAppFullscreen(bool* p_open); static void ShowExampleAppWindowTitles(bool* p_open); static void ShowExampleAppCustomRendering(bool* p_open); static void ShowExampleMenuFile(); @@ -251,6 +253,7 @@ void ImGui::ShowDemoWindow(bool* p_open) // Examples Apps (accessible from the "Examples" menu) static bool show_app_main_menu_bar = false; static bool show_app_documents = false; + static bool show_app_console = false; static bool show_app_log = false; static bool show_app_layout = false; @@ -259,6 +262,7 @@ void ImGui::ShowDemoWindow(bool* p_open) static bool show_app_auto_resize = false; static bool show_app_constrained_resize = false; static bool show_app_simple_overlay = false; + static bool show_app_fullscreen = false; static bool show_app_window_titles = false; static bool show_app_custom_rendering = false; @@ -273,6 +277,7 @@ void ImGui::ShowDemoWindow(bool* p_open) if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay); + if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen); if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); @@ -316,7 +321,8 @@ void ImGui::ShowDemoWindow(bool* p_open) // We specify a default position/size in case there's no data in the .ini file. // We only do it to make the demo applications a little more welcoming, but typically this isn't required. - ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); + const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); // Main body of the Demo window starts here. @@ -354,6 +360,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); + ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen); ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); ImGui::MenuItem("Documents", NULL, &show_app_documents); @@ -584,13 +591,12 @@ static void ShowDemoWindowWidgets() { // Using the _simplified_ one-liner Combo() api here - // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api. + // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; static int item_current = 0; ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); HelpMarker( - "Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, " - "and demonstration of various flags.\n"); + "Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API."); } { @@ -689,14 +695,13 @@ static void ShowDemoWindowWidgets() } { - // List box + // Using the _simplified_ one-liner ListBox() api here + // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; static int item_current = 1; - ImGui::ListBox("listbox\n(single select)", &item_current, items, IM_ARRAYSIZE(items), 4); - - //static int listbox_item_current2 = 2; - //ImGui::SetNextItemWidth(-1); - //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); + ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4); + ImGui::SameLine(); HelpMarker( + "Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); } ImGui::TreePop(); @@ -1009,7 +1014,7 @@ static void ShowDemoWindowWidgets() // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively // stored in the object itself, etc.) const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; - static int item_current_idx = 0; // Here our selection data is an index. + static int item_current_idx = 0; // Here we store our selection data as an index. const char* combo_label = items[item_current_idx]; // Label to preview before opening the combo (technically it could be anything) if (ImGui::BeginCombo("combo 1", combo_label, flags)) { @@ -1042,6 +1047,48 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + if (ImGui::TreeNode("List boxes")) + { + // Using the generic BeginListBox() API, you have full control over how to display the combo contents. + // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + // stored in the object itself, etc.) + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; + static int item_current_idx = 0; // Here we store our selection data as an index. + if (ImGui::BeginListBox("listbox 1")) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_current_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_current_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + + // Custom size: use all width, 5 items tall + ImGui::Text("Full-width:"); + if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing()))) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_current_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_current_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + + ImGui::TreePop(); + } + if (ImGui::TreeNode("Selectables")) { // Selectable() has 2 overloads: @@ -2557,11 +2604,11 @@ static void ShowDemoWindowLayout() ImGui::Button("LEVERAGE\nBUZZWORD", size); ImGui::SameLine(); - if (ImGui::ListBoxHeader("List", size)) + if (ImGui::BeginListBox("List", size)) { ImGui::Selectable("Selected", true); ImGui::Selectable("Not Selected", false); - ImGui::ListBoxFooter(); + ImGui::EndListBox(); } ImGui::TreePop(); @@ -3146,7 +3193,7 @@ static void ShowDemoWindowPopups() { if (ImGui::Selectable("Set to zero")) value = 0.0f; if (ImGui::Selectable("Set to PI")) value = 3.1415f; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); ImGui::EndPopup(); } @@ -3186,7 +3233,7 @@ static void ShowDemoWindowPopups() ImGui::OpenPopup("Delete?"); // Always center this window when appearing - ImVec2 center(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f); + ImVec2 center = ImGui::GetMainViewport()->GetCenter(); ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) @@ -4249,7 +4296,7 @@ static void ShowDemoWindowTables() ImGui::TableHeadersRow(); ImGui::TableNextColumn(); - ImGui::Text("A0 Cell 0"); + ImGui::Text("A0 Row 0"); { float rows_height = TEXT_BASE_HEIGHT * 2; if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) @@ -4260,21 +4307,21 @@ static void ShowDemoWindowTables() ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height); ImGui::TableNextColumn(); - ImGui::Text("B0 Cell 0"); + ImGui::Text("B0 Row 0"); ImGui::TableNextColumn(); - ImGui::Text("B0 Cell 1"); + ImGui::Text("B1 Row 0"); ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height); ImGui::TableNextColumn(); - ImGui::Text("B1 Cell 0"); + ImGui::Text("B0 Row 1"); ImGui::TableNextColumn(); - ImGui::Text("B1 Cell 1"); + ImGui::Text("B1 Row 1"); ImGui::EndTable(); } } - ImGui::TableNextColumn(); ImGui::Text("A0 Cell 1"); - ImGui::TableNextColumn(); ImGui::Text("A1 Cell 0"); - ImGui::TableNextColumn(); ImGui::Text("A1 Cell 1"); + ImGui::TableNextColumn(); ImGui::Text("A1 Row 0"); + ImGui::TableNextColumn(); ImGui::Text("A0 Row 1"); + ImGui::TableNextColumn(); ImGui::Text("A1 Row 1"); ImGui::EndTable(); } ImGui::TreePop(); @@ -6931,23 +6978,29 @@ static void ShowExampleAppConstrainedResize(bool* p_open) } //----------------------------------------------------------------------------- -// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() //----------------------------------------------------------------------------- // Demonstrate creating a simple static window with no decoration // + a context-menu to choose which corner of the screen to use. static void ShowExampleAppSimpleOverlay(bool* p_open) { - const float DISTANCE = 10.0f; + const float PAD = 10.0f; static int corner = 0; ImGuiIO& io = ImGui::GetIO(); ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; if (corner != -1) { - window_flags |= ImGuiWindowFlags_NoMove; - ImVec2 window_pos = ImVec2((corner & 1) ? io.DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? io.DisplaySize.y - DISTANCE : DISTANCE); - ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any! + ImVec2 work_size = viewport->WorkSize; + ImVec2 window_pos, window_pos_pivot; + window_pos.x = (corner & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD); + window_pos.y = (corner & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD); + window_pos_pivot.x = (corner & 1) ? 1.0f : 0.0f; + window_pos_pivot.y = (corner & 2) ? 1.0f : 0.0f; ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); + window_flags |= ImGuiWindowFlags_NoMove; } ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background if (ImGui::Begin("Example: Simple overlay", p_open, window_flags)) @@ -6972,6 +7025,42 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) ImGui::End(); } +//----------------------------------------------------------------------------- +// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() +//----------------------------------------------------------------------------- + +// Demonstrate creating a window covering the entire screen/viewport +static void ShowExampleAppFullscreen(bool* p_open) +{ + static bool use_work_area = true; + static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings; + + // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.) + // Based on your use case you may want one of the other. + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos); + ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size); + + if (ImGui::Begin("Example: Fullscreen window", p_open, flags)) + { + ImGui::Checkbox("Use work area instead of main area", &use_work_area); + ImGui::SameLine(); + HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference."); + + ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration); + ImGui::Indent(); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar); + ImGui::Unindent(); + + if (p_open && ImGui::Button("Close this window")) + *p_open = false; + } + ImGui::End(); +} + //----------------------------------------------------------------------------- // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() //----------------------------------------------------------------------------- @@ -6981,16 +7070,19 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) // Read FAQ section "How can I have multiple widgets with the same label?" for details. static void ShowExampleAppWindowTitles(bool*) { + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + const ImVec2 base_pos = viewport->Pos; + // By default, Windows are uniquely identified by their title. // You can use the "##" and "###" markers to manipulate the display/ID. // Using "##" to display same title but have unique identifier. - ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver); ImGui::Begin("Same title as another window##1"); ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); ImGui::End(); - ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver); ImGui::Begin("Same title as another window##2"); ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); ImGui::End(); @@ -6998,7 +7090,7 @@ static void ShowExampleAppWindowTitles(bool*) // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" char buf[128]; sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); - ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver); ImGui::Begin(buf); ImGui::Text("This window has a changing title."); ImGui::End(); @@ -7061,7 +7153,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) static bool curve_segments_override = false; static int curve_segments_override_v = 8; static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); - ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); + ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f"); ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12); ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override); @@ -7078,6 +7170,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) const ImDrawCornerFlags corners_none = 0; const ImDrawCornerFlags corners_all = ImDrawCornerFlags_All; const ImDrawCornerFlags corners_tl_br = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight; + const float rounding = sz / 5.0f; const int circle_segments = circle_segments_override ? circle_segments_override_v : 0; const int curve_segments = curve_segments_override ? curve_segments_override_v : 0; float x = p.x + 4.0f; @@ -7089,8 +7182,8 @@ static void ShowExampleAppCustomRendering(bool* p_open) draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, corners_none, th); x += sz + spacing; // Square - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_all, th); x += sz + spacing; // Square with all rounded corners - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_all, th); x += sz + spacing; // Square with all rounded corners + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle //draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) @@ -7475,19 +7568,20 @@ void ShowExampleAppDocuments(bool* p_open) { if (!ImGui::IsPopupOpen("Save?")) ImGui::OpenPopup("Save?"); - if (ImGui::BeginPopupModal("Save?")) + if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::Text("Save change to the following items?"); - ImGui::SetNextItemWidth(-1.0f); - if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6)) + float item_height = ImGui::GetTextLineHeightWithSpacing(); + if (ImGui::BeginChildFrame(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height))) { for (int n = 0; n < close_queue.Size; n++) if (close_queue[n]->Dirty) ImGui::Text("%s", close_queue[n]->Name); - ImGui::ListBoxFooter(); + ImGui::EndChildFrame(); } - if (ImGui::Button("Yes", ImVec2(80, 0))) + ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f); + if (ImGui::Button("Yes", button_size)) { for (int n = 0; n < close_queue.Size; n++) { @@ -7499,7 +7593,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button("No", ImVec2(80, 0))) + if (ImGui::Button("No", button_size)) { for (int n = 0; n < close_queue.Size; n++) close_queue[n]->DoForceClose(); @@ -7507,7 +7601,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button("Cancel", ImVec2(80, 0))) + if (ImGui::Button("Cancel", button_size)) { close_queue.clear(); ImGui::CloseCurrentPopup(); diff --git a/imgui/src/imgui/imgui_draw.cpp b/imgui/src/imgui/imgui_draw.cpp index 8a67566..5c11a5b 100644 --- a/imgui/src/imgui/imgui_draw.cpp +++ b/imgui/src/imgui/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.80 +// dear imgui, v1.81 // (drawing and font code) /* @@ -32,7 +32,11 @@ Index of this file: #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif + #include "imgui_internal.h" +#ifdef IMGUI_ENABLE_FREETYPE +#include "misc/freetype/imgui_freetype.h" +#endif #include // vsnprintf, sscanf, printf #if !defined(alloca) @@ -118,7 +122,7 @@ namespace IMGUI_STB_NAMESPACE #endif #ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) -#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION +#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in another compilation unit #define STBRP_STATIC #define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0) #define STBRP_SORT ImQsort @@ -131,8 +135,9 @@ namespace IMGUI_STB_NAMESPACE #endif #endif +#ifdef IMGUI_ENABLE_STB_TRUETYPE #ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) -#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in another compilation unit #define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x)) #define STBTT_free(x,u) ((void)(u), IM_FREE(x)) #define STBTT_assert(x) do { IM_ASSERT(x); } while(0) @@ -153,6 +158,7 @@ namespace IMGUI_STB_NAMESPACE #include "imstb_truetype.h" #endif #endif +#endif // IMGUI_ENABLE_STB_TRUETYPE #if defined(__GNUC__) #pragma GCC diagnostic pop @@ -377,8 +383,8 @@ void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error) CircleSegmentMaxError = max_error; for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++) { - const float radius = i + 1.0f; - const int segment_count = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError); + const float radius = (float)i; + const int segment_count = (i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : 0; CircleSegmentCounts[i] = (ImU8)ImMin(segment_count, 255); } } @@ -1012,11 +1018,12 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) { - if (radius == 0.0f || a_min_of_12 > a_max_of_12) + if (radius == 0.0f) { _Path.push_back(center); return; } + IM_ASSERT(a_min_of_12 <= a_max_of_12); // For legacy reason the PathArcToFast() always takes angles where 2*PI is represented by 12, // but it is possible to set IM_DRAWLIST_ARCFAST_TESSELATION_MULTIPLIER to a higher value. This should compile to a no-op otherwise. @@ -1040,6 +1047,7 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa _Path.push_back(center); return; } + IM_ASSERT(a_min <= a_max); // Note that we are adding a point at both a_min and a_max. // If you are trying to draw a full closed circle you don't want the overlapping points! @@ -1278,7 +1286,7 @@ void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int nu if (num_segments <= 0) { // Automatic segment count - const int radius_idx = (int)radius - 1; + const int radius_idx = (int)radius; if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value else @@ -1308,7 +1316,7 @@ void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, if (num_segments <= 0) { // Automatic segment count - const int radius_idx = (int)radius - 1; + const int radius_idx = (int)radius; if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value else @@ -1710,25 +1718,13 @@ void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int ve ImFontConfig::ImFontConfig() { - FontData = NULL; - FontDataSize = 0; + memset(this, 0, sizeof(*this)); FontDataOwnedByAtlas = true; - FontNo = 0; - SizePixels = 0.0f; OversampleH = 3; // FIXME: 2 may be a better default? OversampleV = 1; - PixelSnapH = false; - GlyphExtraSpacing = ImVec2(0.0f, 0.0f); - GlyphOffset = ImVec2(0.0f, 0.0f); - GlyphRanges = NULL; - GlyphMinAdvanceX = 0.0f; GlyphMaxAdvanceX = FLT_MAX; - MergeMode = false; - RasterizerFlags = 0x00; RasterizerMultiply = 1.0f; EllipsisChar = (ImWchar)-1; - memset(Name, 0, sizeof(Name)); - DstFont = NULL; } //----------------------------------------------------------------------------- @@ -1785,17 +1781,8 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3 ImFontAtlas::ImFontAtlas() { - Locked = false; - Flags = ImFontAtlasFlags_None; - TexID = (ImTextureID)NULL; - TexDesiredWidth = 0; + memset(this, 0, sizeof(*this)); TexGlyphPadding = 1; - - TexPixelsAlpha8 = NULL; - TexPixelsRGBA32 = NULL; - TexWidth = TexHeight = 0; - TexUvScale = ImVec2(0.0f, 0.0f); - TexUvWhitePixel = ImVec2(0.0f, 0.0f); PackIdMouseCursors = PackIdLines = -1; } @@ -2081,7 +2068,26 @@ bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* ou bool ImFontAtlas::Build() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); - return ImFontAtlasBuildWithStbTruetype(this); + + // Select builder + // - Note that we do not reassign to atlas->FontBuilderIO, since it is likely to point to static data which + // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are + // using a hot-reloading scheme that messes up static data, store your own instance of ImFontBuilderIO somewhere + // and point to it instead of pointing directly to return value of the GetBuilderXXX functions. + const ImFontBuilderIO* builder_io = FontBuilderIO; + if (builder_io == NULL) + { +#ifdef IMGUI_ENABLE_FREETYPE + builder_io = ImGuiFreeType::GetBuilderForFreeType(); +#elif defined(IMGUI_ENABLE_STB_TRUETYPE) + builder_io = ImFontAtlasGetBuilderForStbTruetype(); +#else + IM_ASSERT(0); // Invalid Build function +#endif + } + + // Build + return builder_io->FontBuilder_Build(this); } void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor) @@ -2101,6 +2107,7 @@ void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig data[i] = table[data[i]]; } +#ifdef IMGUI_ENABLE_STB_TRUETYPE // Temporary data for one source font (multiple source fonts can be merged into one destination ImFont) // (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.) struct ImFontBuildSrcData @@ -2138,7 +2145,7 @@ static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector* out->push_back((int)(((it - it_begin) << 5) + bit_n)); } -bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) +static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) { IM_ASSERT(atlas->ConfigData.Size > 0); @@ -2391,6 +2398,15 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) return true; } +const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype() +{ + static ImFontBuilderIO io; + io.FontBuilder_Build = ImFontAtlasBuildWithStbTruetype; + return &io; +} + +#endif // IMGUI_ENABLE_STB_TRUETYPE + void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent) { if (!font_config->MergeMode) @@ -2433,7 +2449,7 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa } } -void ImFontAtlasBuildRender1bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value) +void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value) { IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); @@ -2443,6 +2459,16 @@ void ImFontAtlasBuildRender1bppRectFromString(ImFontAtlas* atlas, int x, int y, out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : 0x00; } +void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value) +{ + IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); + IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); + unsigned int* out_pixel = atlas->TexPixelsRGBA32 + x + (y * atlas->TexWidth); + for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w) + for (int off_x = 0; off_x < w; off_x++) + out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : IM_COL32_BLACK_TRANS; +} + static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) { ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors); @@ -2455,15 +2481,30 @@ static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); const int x_for_white = r->X; const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; - ImFontAtlasBuildRender1bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF); - ImFontAtlasBuildRender1bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF); + if (atlas->TexPixelsAlpha8 != NULL) + { + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF); + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF); + } + else + { + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', IM_COL32_WHITE); + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE); + } } else { // Render 4 white pixels IM_ASSERT(r->Width == 2 && r->Height == 2); const int offset = (int)r->X + (int)r->Y * w; - atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + if (atlas->TexPixelsAlpha8 != NULL) + { + atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + } + else + { + atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE; + } } atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y); } @@ -2486,10 +2527,30 @@ static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) // Write each slice IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels - unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; - memset(write_ptr, 0x00, pad_left); - memset(write_ptr + pad_left, 0xFF, line_width); - memset(write_ptr + pad_left + line_width, 0x00, pad_right); + if (atlas->TexPixelsAlpha8 != NULL) + { + unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; + for (unsigned int i = 0; i < pad_left; i++) + *(write_ptr + i) = 0x00; + + for (unsigned int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = 0xFF; + + for (unsigned int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = 0x00; + } + else + { + unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)]; + for (unsigned int i = 0; i < pad_left; i++) + *(write_ptr + i) = IM_COL32_BLACK_TRANS; + + for (unsigned int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = IM_COL32_WHITE; + + for (unsigned int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = IM_COL32_BLACK_TRANS; + } // Calculate UVs for this line ImVec2 uv0 = ImVec2((float)(r->X + pad_left - 1), (float)(r->Y + y)) * atlas->TexUvScale; @@ -2524,7 +2585,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) void ImFontAtlasBuildFinish(ImFontAtlas* atlas) { // Render into our custom data blocks - IM_ASSERT(atlas->TexPixelsAlpha8 != NULL); + IM_ASSERT(atlas->TexPixelsAlpha8 != NULL || atlas->TexPixelsRGBA32 != NULL); ImFontAtlasBuildRenderDefaultTexData(atlas); ImFontAtlasBuildRenderLinesTexData(atlas); @@ -3006,6 +3067,7 @@ void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, floa ImFontGlyph& glyph = Glyphs.back(); glyph.Codepoint = (unsigned int)codepoint; glyph.Visible = (x0 != x1) && (y0 != y1); + glyph.Colored = false; glyph.X0 = x0; glyph.Y0 = y0; glyph.X1 = x1; @@ -3256,6 +3318,8 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col const ImFontGlyph* glyph = FindGlyph(c); if (!glyph || !glyph->Visible) return; + if (glyph->Colored) + col |= ~IM_COL32_A_MASK; float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; pos.x = IM_FLOOR(pos.x); pos.y = IM_FLOOR(pos.y); @@ -3318,6 +3382,8 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col ImDrawIdx* idx_write = draw_list->_IdxWritePtr; unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; + const ImU32 col_untinted = col | ~IM_COL32_A_MASK; + while (s < text_end) { if (word_wrap_enabled) @@ -3423,14 +3489,17 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col } } + // Support for untinted glyphs + ImU32 glyph_col = glyph->Colored ? col_untinted : col; + // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: { idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2); idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3); - vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; - vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; - vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; - vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; + vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; + vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; + vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; + vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; vtx_write += 4; vtx_current_idx += 4; idx_write += 6; diff --git a/imgui/src/imgui/imgui_impl_opengl3.cpp b/imgui/src/imgui/imgui_impl_opengl3.cpp index b582851..f3b2a93 100644 --- a/imgui/src/imgui/imgui_impl_opengl3.cpp +++ b/imgui/src/imgui/imgui_impl_opengl3.cpp @@ -13,7 +13,6 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer. // 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state. // 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state. // 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x) @@ -248,7 +247,7 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); diff --git a/imgui/src/imgui/imgui_internal.h b/imgui/src/imgui/imgui_internal.h index dff845a..39caf6b 100644 --- a/imgui/src/imgui/imgui_internal.h +++ b/imgui/src/imgui/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.80 +// dear imgui, v1.81 // (internal structures/api) // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! @@ -29,7 +29,8 @@ Index of this file: // [SECTION] ImGuiWindowTempData, ImGuiWindow // [SECTION] Tab bar, Tab item support // [SECTION] Table support -// [SECTION] Internal API +// [SECTION] ImGui internal API +// [SECTION] ImFontAtlas internal API // [SECTION] Test Engine specific hooks (imgui_test_engine) */ @@ -83,6 +84,12 @@ Index of this file: #error Use IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS #endif +// Enable stb_truetype by default unless FreeType is enabled. +// You can compile with both by defining both IMGUI_ENABLE_FREETYPE and IMGUI_ENABLE_STB_TRUETYPE together. +#ifndef IMGUI_ENABLE_FREETYPE +#define IMGUI_ENABLE_STB_TRUETYPE +#endif + //----------------------------------------------------------------------------- // [SECTION] Forward declarations //----------------------------------------------------------------------------- @@ -610,6 +617,7 @@ struct IMGUI_API ImChunkStream //----------------------------------------------------------------------------- // ImDrawList: Helper function to calculate a circle's segment count given its radius and a "maximum error" value. +// FIXME: the minimum number of auto-segment may be undesirably high for very small radiuses (e.g. 1.0f) #define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN 12 #define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX 512 #define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR) ImClamp((int)((IM_PI * 2.0f) / ImAcos(((_RAD) - (_MAXERROR)) / (_RAD))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) @@ -633,7 +641,7 @@ struct IMGUI_API ImDrawListSharedData // [Internal] Lookup tables ImVec2 ArcFastVtx[12 * IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER]; // FIXME: Bake rounded corners fill/borders in atlas - ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius (array index + 1) before we calculate it dynamically (to avoid calculation overhead) + ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead) const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas ImDrawListSharedData(); @@ -644,8 +652,9 @@ struct ImDrawDataBuilder { ImVector Layers[2]; // Global layers for: regular, tooltip - void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } - void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } + void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } + void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } + int GetDrawListCount() const { int count = 0; for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) count += Layers[n].Size; return count; } IMGUI_API void FlattenIntoSingleLayer(); }; @@ -1138,9 +1147,26 @@ struct ImGuiOldColumns // [SECTION] Viewport support //----------------------------------------------------------------------------- -#ifdef IMGUI_HAS_VIEWPORT -// -#endif // #ifdef IMGUI_HAS_VIEWPORT +// ImGuiViewport Private/Internals fields (cardinal sin: we are using inheritance!) +// Every instance of ImGuiViewport is in fact a ImGuiViewportP. +struct ImGuiViewportP : public ImGuiViewport +{ + int DrawListsLastFrame[2]; // Last frame number the background (0) and foreground (1) draw lists were used + ImDrawList* DrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. + ImDrawData DrawDataP; + ImDrawDataBuilder DrawDataBuilder; + + ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!) + ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height). + ImVec2 CurrWorkOffsetMin; // Work Area: Offset being built/increased during current frame + ImVec2 CurrWorkOffsetMax; // Work Area: Offset being built/decreased during current frame + + ImGuiViewportP() { DrawListsLastFrame[0] = DrawListsLastFrame[1] = -1; DrawLists[0] = DrawLists[1] = NULL; } + ~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); } + ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); } + void UpdateWorkRect() { WorkPos = ImVec2(Pos.x + WorkOffsetMin.x, Pos.y + WorkOffsetMin.y); WorkSize = ImVec2(ImMax(0.0f, Size.x - WorkOffsetMin.x + WorkOffsetMax.x), ImMax(0.0f, Size.y - WorkOffsetMin.y + WorkOffsetMax.y)); } +}; //----------------------------------------------------------------------------- // [SECTION] Settings support @@ -1222,10 +1248,11 @@ struct IMGUI_API ImGuiStackSizes //----------------------------------------------------------------------------- typedef void (*ImGuiContextHookCallback)(ImGuiContext* ctx, ImGuiContextHook* hook); -enum ImGuiContextHookType { ImGuiContextHookType_NewFramePre, ImGuiContextHookType_NewFramePost, ImGuiContextHookType_EndFramePre, ImGuiContextHookType_EndFramePost, ImGuiContextHookType_RenderPre, ImGuiContextHookType_RenderPost, ImGuiContextHookType_Shutdown }; +enum ImGuiContextHookType { ImGuiContextHookType_NewFramePre, ImGuiContextHookType_NewFramePost, ImGuiContextHookType_EndFramePre, ImGuiContextHookType_EndFramePost, ImGuiContextHookType_RenderPre, ImGuiContextHookType_RenderPost, ImGuiContextHookType_Shutdown, ImGuiContextHookType_PendingRemoval_ }; struct ImGuiContextHook { + ImGuiID HookId; // A unique ID assigned by AddContextHook() ImGuiContextHookType Type; ImGuiID Owner; ImGuiContextHookCallback Callback; @@ -1323,6 +1350,9 @@ struct ImGuiContext ImVectorOpenPopupStack; // Which popups are open (persistent) ImVectorBeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) + // Viewports + ImVector Viewports; // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData. + // Gamepad/keyboard Navigation ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusWindow' ImGuiID NavId; // Focused item for navigation @@ -1380,11 +1410,7 @@ struct ImGuiContext bool FocusTabPressed; // // Render - ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user - ImDrawDataBuilder DrawDataBuilder; float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list) - ImDrawList BackgroundDrawList; // First draw list to be rendered. - ImDrawList ForegroundDrawList; // Last draw list to be rendered. This is where we the render software mouse cursor (if io.MouseDrawCursor is set) and most debug overlays. ImGuiMouseCursor MouseCursor; // Drag and Drop @@ -1453,12 +1479,15 @@ struct ImGuiContext ImChunkStream SettingsWindows; // ImGuiWindow .ini settings entries ImChunkStream SettingsTables; // ImGuiTable .ini settings entries ImVector Hooks; // Hooks for extensions (e.g. test engine) + ImGuiID HookIdNext; // Next available HookId // Capture/Logging bool LogEnabled; // Currently capturing ImGuiLogType LogType; // Capture target ImFileHandle LogFile; // If != NULL log to stdout/ file ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. + const char* LogNextPrefix; + const char* LogNextSuffix; float LogLinePosY; bool LogLineFirstItem; int LogDepthRef; @@ -1479,7 +1508,7 @@ struct ImGuiContext int WantTextInputNextFrame; char TempBuffer[1024 * 3 + 1]; // Temporary text buffer - ImGuiContext(ImFontAtlas* shared_font_atlas) : BackgroundDrawList(&DrawListSharedData), ForegroundDrawList(&DrawListSharedData) + ImGuiContext(ImFontAtlas* shared_font_atlas) { Initialized = false; FontAtlasOwnedByContext = shared_font_atlas ? false : true; @@ -1568,8 +1597,6 @@ struct ImGuiContext FocusTabPressed = false; DimBgRatio = 0.0f; - BackgroundDrawList._OwnerName = "##Background"; // Give it a name for debugging - ForegroundDrawList._OwnerName = "##Foreground"; // Give it a name for debugging MouseCursor = ImGuiMouseCursor_Arrow; DragDropActive = DragDropWithinSource = DragDropWithinTarget = false; @@ -1606,9 +1633,11 @@ struct ImGuiContext SettingsLoaded = false; SettingsDirtyTimer = 0.0f; + HookIdNext = 0; LogEnabled = false; LogType = ImGuiLogType_None; + LogNextPrefix = LogNextSuffix = NULL; LogFile = NULL; LogLinePosY = FLT_MAX; LogLineFirstItem = false; @@ -1681,10 +1710,10 @@ struct IMGUI_API ImGuiWindowTempData // Local parameters stacks // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. ImGuiItemFlags ItemFlags; // == g.ItemFlagsStack.back() - float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window - float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] - ImVector ItemWidthStack; - ImVector TextWrapPosStack; + float ItemWidth; // Current item width (>0.0: width in pixels, <0.0: align xx pixels to the right of window). + float TextWrapPos; // Current text wrap pos. + ImVector ItemWidthStack; // Store item widths to restore (attention: .back() is not == ItemWidth) + ImVector TextWrapPosStack; // Store text wrap pos to restore (attention: .back() is not == TextWrapPos) ImGuiStackSizes StackSizesOnBegin; // Store size of various stacks for asserting }; @@ -2072,7 +2101,7 @@ struct ImGuiTable ImGuiTableColumnIdx FreezeColumnsCount; // Actual frozen columns count (== FreezeColumnsRequest, or == 0 when no scrolling offset) ImGuiTableColumnIdx RowCellDataCurrent; // Index of current RowCellData[] entry in current row ImGuiTableDrawChannelIdx DummyDrawChannel; // Redirect non-visible columns here. - ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; // For Selectable() and other widgets drawing accross columns after the freezing line. Index within DrawSplitter.Channels[] + ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; // For Selectable() and other widgets drawing across columns after the freezing line. Index within DrawSplitter.Channels[] ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen; bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row. bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). @@ -2086,7 +2115,7 @@ struct ImGuiTable bool IsResetAllRequest; bool IsResetDisplayOrderRequest; bool IsUnfrozenRows; // Set when we got past the frozen row. - bool IsDefaultSizingPolicy; // Set if user didn't explicitely set a sizing policy in BeginTable() + bool IsDefaultSizingPolicy; // Set if user didn't explicitly set a sizing policy in BeginTable() bool MemoryCompacted; bool HostSkipItems; // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis @@ -2135,7 +2164,7 @@ struct ImGuiTableSettings #endif // #ifdef IMGUI_HAS_TABLE //----------------------------------------------------------------------------- -// [SECTION] Internal API +// [SECTION] ImGui internal API // No guarantee of forward compatibility here! //----------------------------------------------------------------------------- @@ -2171,7 +2200,9 @@ namespace ImGui // Fonts, drawing IMGUI_API void SetCurrentFont(ImFont* font); inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } - inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); ImGuiContext& g = *GImGui; return &g.ForegroundDrawList; } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. + inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. + IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. + IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. // Init IMGUI_API void Initialize(ImGuiContext* context); @@ -2184,7 +2215,8 @@ namespace ImGui IMGUI_API void UpdateMouseMovingWindowEndFrame(); // Generic context hooks - IMGUI_API void AddContextHook(ImGuiContext* context, const ImGuiContextHook* hook); + IMGUI_API ImGuiID AddContextHook(ImGuiContext* context, const ImGuiContextHook* hook); + IMGUI_API void RemoveContextHook(ImGuiContext* context, ImGuiID hook_to_remove); IMGUI_API void CallContextHooks(ImGuiContext* context, ImGuiContextHookType type); // Settings @@ -2241,6 +2273,8 @@ namespace ImGui // Logging/Capture IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer + IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); + IMGUI_API void LogSetNextTextDecoration(const char* prefix, const char* suffix); // Popups, Modals, Tooltips IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags); @@ -2306,6 +2340,7 @@ namespace ImGui // Tables: Candidates for public API IMGUI_API void TableOpenContextMenu(int column_n = -1); + IMGUI_API void TableSetColumnEnabled(int column_n, bool enabled); IMGUI_API void TableSetColumnWidth(int column_n, float width); IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. @@ -2378,7 +2413,6 @@ namespace ImGui IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0); IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. - IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); // Render helpers (those functions don't access any ImGui state!) IMGUI_API void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f); @@ -2469,7 +2503,7 @@ namespace ImGui IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns); IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label); - IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow* window, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); + IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label); IMGUI_API void DebugNodeTable(ImGuiTable* table); @@ -2477,18 +2511,32 @@ namespace ImGui IMGUI_API void DebugNodeWindow(ImGuiWindow* window, const char* label); IMGUI_API void DebugNodeWindowSettings(ImGuiWindowSettings* settings); IMGUI_API void DebugNodeWindowsList(ImVector* windows, const char* label); + IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport); + IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb); } // namespace ImGui -// ImFontAtlas internals -IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); -IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); -IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildRender1bppRectFromString(ImFontAtlas* atlas, int atlas_x, int atlas_y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value); -IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); -IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); + +//----------------------------------------------------------------------------- +// [SECTION] ImFontAtlas internal API +//----------------------------------------------------------------------------- + +// This structure is likely to evolve as we add support for incremental atlas updates +struct ImFontBuilderIO +{ + bool (*FontBuilder_Build)(ImFontAtlas* atlas); +}; + +// Helper for font builder +IMGUI_API const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype(); +IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); +IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); +IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value); +IMGUI_API void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value); +IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); +IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); //----------------------------------------------------------------------------- // [SECTION] Test Engine specific hooks (imgui_test_engine) diff --git a/imgui/src/imgui/imgui_tables.cpp b/imgui/src/imgui/imgui_tables.cpp index 19fa625..61a84f9 100644 --- a/imgui/src/imgui/imgui_tables.cpp +++ b/imgui/src/imgui/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.80 +// dear imgui, v1.81 // (tables and columns code) /* @@ -126,12 +126,12 @@ Index of this file: // - with Table policy ImGuiTableFlags_SizingFixedSame --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is max of all contents width // - with Table policy ImGuiTableFlags_SizingStretchSame --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is 1.0f // - with Table policy ImGuiTableFlags_SizingStretchWeight --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is proportional to contents -// Default Width and default Weight can be overriden when calling TableSetupColumn(). +// Default Width and default Weight can be overridden when calling TableSetupColumn(). //----------------------------------------------------------------------------- // About mixing Fixed/Auto and Stretch columns together: // - the typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. // - using mixed policies with ScrollX does not make much sense, as using Stretch columns with ScrollX does not make much sense in the first place! -// that is, unless 'inner_width' is passed to BeginTable() to explicitely provide a total width to layout columns in. +// that is, unless 'inner_width' is passed to BeginTable() to explicitly provide a total width to layout columns in. // - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the maximum contents width. // - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weight/widths. //----------------------------------------------------------------------------- @@ -1367,7 +1367,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo // Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa. // Give a grace to users of ImGuiTableFlags_ScrollX. if (table->IsDefaultSizingPolicy && (flags & ImGuiTableColumnFlags_WidthMask_) == 0 && (flags & ImGuiTableFlags_ScrollX) == 0) - IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitely in either Table or Column."); + IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitly in either Table or Column."); // When passing a width automatically enforce WidthFixed policy // (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable) @@ -1460,6 +1460,21 @@ const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n) return &table->ColumnsNames.Buf[column->NameOffset]; } +// For the getter you can use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsEnabled) +void ImGui::TableSetColumnEnabled(int column_n, bool enabled) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL); + if (!table) + return; + if (column_n < 0) + column_n = table->CurrentColumn; + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiTableColumn* column = &table->Columns[column_n]; + column->IsEnabledNextFrame = enabled; +} + // We allow querying for an extra column in order to poll the IsHovered state of the right-most section ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n) { @@ -1639,6 +1654,10 @@ void ImGui::TableEndRow(ImGuiTable* table) if (table->CurrentColumn != -1) TableEndCell(table); + // Logging + if (g.LogEnabled) + LogRenderedText(NULL, "|"); + // Position cursor at the bottom of our row so it can be used for e.g. clipping calculation. However it is // likely that the next call to TableBeginCell() will reposition the cursor to take account of vertical padding. window->DC.CursorPos.y = table->RowPosY2; @@ -1875,6 +1894,14 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n) SetWindowClipRectBeforeSetChannel(window, column->ClipRect); table->DrawSplitter.SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); } + + // Logging + ImGuiContext& g = *GImGui; + if (g.LogEnabled && !column->IsSkipItems) + { + LogRenderedText(&window->DC.CursorPos, "|"); + g.LogLinePosY = FLT_MAX; + } } // [Internal] Called by TableNextRow()/TableSetColumnIndex()/TableNextColumn() diff --git a/imgui/src/imgui/imgui_widgets.cpp b/imgui/src/imgui/imgui_widgets.cpp index 931e8ec..d2a4d1d 100644 --- a/imgui/src/imgui/imgui_widgets.cpp +++ b/imgui/src/imgui/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.80 +// dear imgui, v1.81 // (widgets code) /* @@ -692,6 +692,9 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderNavHighlight(bb, id); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); + + if (g.LogEnabled) + LogSetNextTextDecoration("[", "]"); RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); // Automatically close popups @@ -1097,10 +1100,11 @@ bool ImGui::Checkbox(const char* label, bool* v) RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f); } + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); if (g.LogEnabled) - LogRenderedText(&total_bb.Min, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); + LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); if (label_size.x > 0.0f) - RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); + RenderText(label_pos, label); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); return pressed; @@ -1198,10 +1202,11 @@ bool ImGui::RadioButton(const char* label, bool active) window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize); } + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); if (g.LogEnabled) - LogRenderedText(&total_bb.Min, active ? "(x)" : "( )"); + LogRenderedText(&label_pos, active ? "(x)" : "( )"); if (label_size.x > 0.0f) - RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); + RenderText(label_pos, label); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); return pressed; @@ -1385,7 +1390,8 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) // Draw window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator)); if (g.LogEnabled) - LogRenderedText(&bb.Min, "--------------------------------"); + LogRenderedText(&bb.Min, "--------------------------------\n"); + } if (columns) { @@ -1576,7 +1582,12 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF } RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding); if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) - RenderTextClipped(frame_bb.Min + style.FramePadding, ImVec2(value_x2, frame_bb.Max.y), preview_value, NULL, NULL, ImVec2(0.0f, 0.0f)); + { + ImVec2 preview_pos = frame_bb.Min + style.FramePadding; + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(preview_pos, ImVec2(value_x2, frame_bb.Max.y), preview_value, NULL, NULL, ImVec2(0.0f, 0.0f)); + } if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -2326,6 +2337,8 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); if (label_size.x > 0.0f) @@ -2589,7 +2602,7 @@ template TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) { if (v_min == v_max) - return (TYPE)0.0f; + return v_min; const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); TYPE result; @@ -2938,6 +2951,8 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); if (label_size.x > 0.0f) @@ -3853,9 +3868,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); - PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); - bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding); - PopStyleVar(3); + bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove); + PopStyleVar(2); PopStyleColor(); if (!child_visible) { @@ -3865,6 +3879,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } draw_window = g.CurrentWindow; // Child window draw_window->DC.NavLayerActiveMaskNext |= (1 << draw_window->DC.NavLayerCurrent); // This is to ensure that EndChild() will display a navigation highlight so we can "enter" into it. + draw_window->DC.CursorPos += style.FramePadding; inner_size.x -= draw_window->ScrollbarSizes.x; } else @@ -4025,7 +4040,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Edit in progress const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX; - const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize * 0.5f)); + const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f)); const bool is_osx = io.ConfigMacOSXBehaviors; if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0])) @@ -4474,10 +4489,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll)) { const float scroll_increment_x = inner_size.x * 0.25f; + const float visible_width = inner_size.x - style.FramePadding.x; if (cursor_offset.x < state->ScrollX) state->ScrollX = IM_FLOOR(ImMax(0.0f, cursor_offset.x - scroll_increment_x)); - else if (cursor_offset.x - inner_size.x >= state->ScrollX) - state->ScrollX = IM_FLOOR(cursor_offset.x - inner_size.x + scroll_increment_x); + else if (cursor_offset.x - visible_width >= state->ScrollX) + state->ScrollX = IM_FLOOR(cursor_offset.x - visible_width + scroll_increment_x); } else { @@ -4582,14 +4598,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline) { - Dummy(text_size); + Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); EndChild(); EndGroup(); } // Log as text if (g.LogEnabled && (!is_password || is_displaying_hint)) + { + LogSetNextTextDecoration("{", "}"); LogRenderedText(&draw_pos, buf_display, buf_display_end); + } if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -5796,19 +5815,10 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l text_pos.x -= text_offset_x; if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) frame_bb.Max.x -= g.FontSize + style.FramePadding.x; + if (g.LogEnabled) - { - // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here. - const char log_prefix[] = "\n##"; - const char log_suffix[] = "##"; - LogRenderedText(&text_pos, log_prefix, log_prefix + 3); - RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); - LogRenderedText(&text_pos, log_suffix, log_suffix + 2); - } - else - { - RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); - } + LogSetNextTextDecoration("###", "###"); + RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); } else { @@ -5824,7 +5834,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l else if (!is_leaf) RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f); if (g.LogEnabled) - LogRenderedText(&text_pos, ">"); + LogSetNextTextDecoration(">", NULL); RenderText(text_pos, label, label_end, false); } @@ -5975,7 +5985,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl ItemSize(size, 0.0f); // Fill horizontal space - // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitely right-aligned sizes not visibly match other widgets. + // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly right-aligned sizes not visibly match other widgets. const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0; const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x; const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x; @@ -6114,18 +6124,14 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags //------------------------------------------------------------------------- // [SECTION] Widgets: ListBox //------------------------------------------------------------------------- +// - BeginListBox() +// - EndListBox() // - ListBox() -// - ListBoxHeader() -// - ListBoxFooter() -//------------------------------------------------------------------------- -// FIXME: This is an old API. We should redesign some of it, rename ListBoxHeader->BeginListBox, ListBoxFooter->EndListBox -// and promote using them over existing ListBox() functions, similarly to change with combo boxes. //------------------------------------------------------------------------- -// FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature. -// Helper to calculate the size of a listbox and display a label on the right. -// Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty" -bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) +// Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty" +// Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.25 * item_height). +bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -6136,12 +6142,12 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) const ImGuiID id = GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. - ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); + // Size default to hold ~7.25 items. + // Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. + ImVec2 size = ImFloor(CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.25f + style.FramePadding.y * 2.0f)); ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); - window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy. g.NextItemData.ClearFlags(); if (!IsRectVisible(bb.Min, bb.Max)) @@ -6151,50 +6157,41 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) return false; } + // FIXME-OPT: We could omit the BeginGroup() if label_size.x but would need to omit the EndGroup() as well. BeginGroup(); - if (label_size.x > 0) - RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + if (label_size.x > 0.0f) + { + ImVec2 label_pos = ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y); + RenderText(label_pos, label); + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size); + } BeginChildFrame(id, frame_bb.GetSize()); return true; } -// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// OBSOLETED in 1.81 (from February 2021) bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) { - // Size default to hold ~7.25 items. - // We add +25% worth of item height to allow the user to see at a glance if there are more items up/down, without looking at the scrollbar. - // We don't add this extra bit if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size. - // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution. - if (height_in_items < 0) - height_in_items = ImMin(items_count, 7); - const ImGuiStyle& style = GetStyle(); - float height_in_items_f = (height_in_items < items_count) ? (height_in_items + 0.25f) : (height_in_items + 0.00f); - - // We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild(). + // If height_in_items == -1, default height is maximum 7. + ImGuiContext& g = *GImGui; + float height_in_items_f = (height_in_items < 0 ? ImMin(items_count, 7) : height_in_items) + 0.25f; ImVec2 size; size.x = 0.0f; - size.y = ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + style.FramePadding.y * 2.0f); - return ListBoxHeader(label, size); + size.y = GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f; + return BeginListBox(label, size); } +#endif -// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. -void ImGui::ListBoxFooter() +void ImGui::EndListBox() { - ImGuiWindow * window = GetCurrentWindow(); - IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched ListBoxHeader/ListBoxFooter calls. Did you test the return value of ListBoxHeader()?"); - ImGuiWindow* parent_window = window->ParentWindow; - const ImRect bb = parent_window->DC.LastItemRect; - const ImGuiStyle& style = GetStyle(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched BeginListBox/EndListBox calls. Did you test the return value of BeginListBox?"); EndChildFrame(); - - // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect) - // We call SameLine() to restore DC.CurrentLine* data - SameLine(); - parent_window->DC.CursorPos = bb.Min; - ItemSize(bb, style.FramePadding.y); - EndGroup(); + EndGroup(); // This is only required to be able to do IsItemXXX query on the whole ListBox including label } bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items) @@ -6203,25 +6200,35 @@ bool ImGui::ListBox(const char* label, int* current_item, const char* const item return value_changed; } +// This is merely a helper around BeginListBox(), EndListBox(). +// Considering using those directly to submit custom data or store selection differently. bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items) { - if (!ListBoxHeader(label, items_count, height_in_items)) + ImGuiContext& g = *GImGui; + + // Calculate size from "height_in_items" + if (height_in_items < 0) + height_in_items = ImMin(items_count, 7); + float height_in_items_f = height_in_items + 0.25f; + ImVec2 size(0.0f, ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f)); + + if (!BeginListBox(label, size)) return false; - // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper. - ImGuiContext& g = *GImGui; + // Assume all items have even height (= 1 line of text). If you need items of different height, + // you can create a custom version of ListBox() in your code without using the clipper. bool value_changed = false; ImGuiListClipper clipper; clipper.Begin(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - const bool item_selected = (i == *current_item); const char* item_text; if (!items_getter(data, i, &item_text)) item_text = "*Unknown item*"; PushID(i); + const bool item_selected = (i == *current_item); if (Selectable(item_text, item_selected)) { *current_item = i; @@ -6231,7 +6238,7 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v SetItemDefaultFocus(); PopID(); } - ListBoxFooter(); + EndListBox(); if (value_changed) MarkItemEdited(g.CurrentWindow->DC.LastItemId); @@ -6513,7 +6520,7 @@ bool ImGui::BeginMenuBar() clip_rect.ClipWith(window->OuterRectClipped); PushClipRect(clip_rect.Min, clip_rect.Max, false); - // We overwrite CursorMaxPos because BeginGroup sets it to CursorPos (essentially the .EmitItem hack in EndMenuBar() would need something analoguous here, maybe a BeginGroupEx() with flags). + // We overwrite CursorMaxPos because BeginGroup sets it to CursorPos (essentially the .EmitItem hack in EndMenuBar() would need something analogous here, maybe a BeginGroupEx() with flags). window->DC.CursorPos = window->DC.CursorMaxPos = 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 = ImGuiNavLayer_Menu; @@ -6562,18 +6569,39 @@ void ImGui::EndMenuBar() window->DC.MenuBarAppending = 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; + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); + ImGuiWindow* menu_bar_window = FindWindowByName("##MainMenuBar"); + + // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. 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.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y)); + + // Get our rectangle at the top of the work area + if (menu_bar_window == NULL || menu_bar_window->BeginCount == 0) + { + // Set window position + // We don't attempt to calculate our height ahead, as it depends on the per-viewport font size. + // However menu-bar will affect the minimum window size so we'll get the right height. + ImVec2 menu_bar_pos = viewport->Pos + viewport->CurrWorkOffsetMin; + ImVec2 menu_bar_size = ImVec2(viewport->Size.x - viewport->CurrWorkOffsetMin.x + viewport->CurrWorkOffsetMax.x, 1.0f); + SetNextWindowPos(menu_bar_pos); + SetNextWindowSize(menu_bar_size); + } + + // Create window PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); + PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint, however the presence of a menu-bar will give us the minimum height we want. ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar(); PopStyleVar(2); + + // Report our size into work area (for next frame) using actual window size + menu_bar_window = GetCurrentWindow(); + if (menu_bar_window->BeginCount == 1) + viewport->CurrWorkOffsetMin.y += menu_bar_window->Size.y; + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); if (!is_open) { @@ -6749,7 +6777,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) if (menu_is_open) { - SetNextWindowPos(popup_pos, ImGuiCond_Always); + SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: this is super misleading! The value will serve as reference for FindBestWindowPosForPopup(), not actual pos. menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) } else diff --git a/imgui/src/imgui/imstb_truetype.h b/imgui/src/imgui/imstb_truetype.h index b4bdbd8..fc815d7 100644 --- a/imgui/src/imgui/imstb_truetype.h +++ b/imgui/src/imgui/imstb_truetype.h @@ -4302,7 +4302,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex int winding = 0; orig[0] = x; - //orig[1] = y; // [DEAR IMGUI] commmented double assignment + //orig[1] = y; // [DEAR IMGUI] commented double assignment // make sure y never passes through a vertex of the shape y_frac = (float) STBTT_fmod(y, 1.0f);