From d1d5075b66f93686954154ceaba7fe30abc41f4b Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 6 May 2019 14:17:39 +0200 Subject: [PATCH 01/11] Version 1.70 --- docs/CHANGELOG.txt | 2 +- docs/TODO.txt | 14 ++++++++++++-- examples/README.txt | 2 +- imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_widgets.cpp | 2 +- misc/fonts/README.txt | 2 +- 10 files changed, 23 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1e4d8a23..cafaa6bb 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -30,7 +30,7 @@ HOW TO UPDATE? ----------------------------------------------------------------------- - VERSION 1.70 WIP (In Progress) + VERSION 1.70 (Released 2019-05-06) ----------------------------------------------------------------------- Breaking Changes: diff --git a/docs/TODO.txt b/docs/TODO.txt index 2dbf1f0f..4c89c8e3 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -27,6 +27,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - window: investigate better auto-positioning for new windows. - window/opt: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate. -> this may require enforcing that it is illegal to submit contents if Begin returns false. - window/child: the first draw command of a child window could be moved into the current draw command of the parent window (unless child+tooltip?). + - window/child: border could be emitted in parent as well. - window/clipping: some form of clipping when DisplaySize (or corresponding viewport) is zero. - window/tab: add a way to signify that a window or docked window requires attention (e.g. blinking title bar). - scrolling: while holding down a scrollbar, try to keep the same contents visible (at least while not moving mouse) @@ -65,6 +66,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - widgets: a way to represent "mixed" values, so e.g. all values replaced with **, including check-boxes, colors, etc. with support for multi-components widgets (e.g. SliderFloat3, make only "Y" mixed) - widgets: selectable: generic BeginSelectable()/EndSelectable() mechanism. - widgets: selectable: a way to visualize partial/mixed selection (e.g. parent tree node has children with mixed selection) + - widgets: checkbox with custom glyph inside frame. - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now and super fragile. - input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541) @@ -170,6 +172,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - listbox: keyboard navigation. - listbox: disable capturing mouse wheel if the listbox has no scrolling. (#1681) - listbox: scrolling should track modified selection. + - listbox: future api should allow to enable horizontal scrolling (#2510) !- popups/menus: clarify usage of popups id, how MenuItem/Selectable closing parent popups affects the ID, etc. this is quite fishy needs improvement! (#331, #402) - popups/modal: make modal title bar blink when trying to click outside the modal @@ -236,15 +239,19 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - filters: fuzzy matches (may use code at blog.forrestthewoods.com/4cffeed33fdb) - drag and drop: drag tooltip hovering over source widget with IsItemHovered/SetTooltip flickers. + - drag and drop: fix/support/options for overlapping drag sources. - drag and drop: releasing a drop shows the "..." tooltip for one frame - since e13e598 (#1725) + - drag and drop: drag source on a group object (would need e.g. an invisible button covering group in EndGroup) https://twitter.com/paniq/status/1121446364909535233 - drag and drop: have some way to know when a drag begin from BeginDragDropSource() pov. - drag and drop: allow preview tooltip to be submitted from a different place than the drag source. (#1725) - drag and drop: allow using with other mouse buttons (where activeid won't be set). (#1637) - drag and drop: make it easier and provide a demo to have tooltip both are source and target site, with a more detailed one on target site (tooltip ordering problem) - - drag and drop: test with reordering nodes (in a list, or a tree node). (#143) + - drag and drop: demo with reordering nodes (in a list, or a tree node). (#143) - drag and drop: test integrating with os drag and drop (make it easy to do a naive WM_DROPFILE integration) + - drag and drop: allow for multiple payload types. (#143) - drag and drop: make payload optional? (#143) - - drag and drop: feedback when hovering a modal (cursor?) + - drag and drop: (#143) "both an in-process pointer and a promise to generate a serialized version, for whether the drag ends inside or outside the same process" + - drag and drop: feedback when hovering a region blocked by modal (mouse cursor "NO"?) - node/graph editor (#306) - pie menus patterns (#434) - markup: simple markup language for color change? (#902) @@ -267,6 +274,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - font/draw: vertical and/or rotated text renderer (#705) - vertical is easier clipping wise - font/draw: need to be able to specify wrap start position. - font/draw: better reserve policy for large horizontal block of text (shouldn't reserve for all clipped lines) + - font/draw: underline, squiggle line rendering helpers. - font: optimization: for monospace font (like the default one) we can trim IndexXAdvance as long as trailing value is == FallbackXAdvance (need to make sure TAB is still correct), would save on cache line. - font: add support for kerning, probably optional. A) perhaps default to (32..128)^2 matrix ~ 9K entries = 36KB, then hash for non-ascii?. B) or sparse lookup into per-char list? - font: add a simpler CalcTextSizeA() api? current one ok but not welcome if user needs to call it directly (without going through ImGui::CalcTextSize) @@ -309,6 +317,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - inputs: support track pad style scrolling & slider edit. - inputs/io: backspace and arrows in the context of a text input could use system repeat rate. - inputs/io: clarify/standardize/expose repeat rate and repeat delays (#1808) + - inputs: add mouse cursor for unavailable/no? IDC_NO/SDL_SYSTEM_CURSOR_NO. - misc: idle: expose "woken up" boolean (set by inputs) and/or animation time (for cursor blink) for back-end to be able stop refreshing easily. - misc: idle: if cursor blink if the _only_ visible animation, core imgui could rewrite vertex alpha to avoid CPU pass on ImGui:: calls. @@ -326,6 +335,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - remote: make a system like RemoteImGui first-class citizen/project (#75) - demo: find a way to demonstrate textures in the examples application, as it such a common issue for new users. + - demo: demonstrate using PushStyleVar() in more details. - demo: add vertical separator demo - demo: add virtual scrolling example? - demo: demonstrate Plot offset diff --git a/examples/README.txt b/examples/README.txt index 6a34c076..0be7ff6a 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -1,5 +1,5 @@ ----------------------------------------------------------------------- - dear imgui, v1.70 WIP + dear imgui, v1.70 ----------------------------------------------------------------------- examples/README.txt (This is the README file for the examples/ folder. See docs/ for more documentation) diff --git a/imgui.cpp b/imgui.cpp index 1351d285..0bcaee50 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.70 WIP +// dear imgui, v1.70 // (main code and documentation) // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. diff --git a/imgui.h b/imgui.h index 774c1b51..423ba3ac 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.70 WIP +// dear imgui, v1.70 // (headers) // See imgui.cpp file for documentation. @@ -46,8 +46,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.70 WIP" -#define IMGUI_VERSION_NUM 16991 +#define IMGUI_VERSION "1.70" +#define IMGUI_VERSION_NUM 17000 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) // Define attributes of all API symbols declarations (e.g. for DLL under Windows) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 0d9c50a1..62196c64 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.70 WIP +// dear imgui, v1.70 // (demo code) // Message to the person tempted to delete this file when integrating Dear ImGui into their code base: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5d493600..63d99a29 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.70 WIP +// dear imgui, v1.70 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 4130ab8a..cc98c20b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.70 WIP +// dear imgui, v1.70 // (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! diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f146920d..5b3ea581 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.70 WIP +// dear imgui, v1.70 // (widgets code) /* diff --git a/misc/fonts/README.txt b/misc/fonts/README.txt index a9f61cdb..5c475f2f 100644 --- a/misc/fonts/README.txt +++ b/misc/fonts/README.txt @@ -1,4 +1,4 @@ -dear imgui, v1.70 WIP +dear imgui, v1.70 (Font Readme) --------------------------------------- From 42fc563feda4acbac1c63336d4fdd1f50fd87a2d Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 7 May 2019 16:36:08 +0200 Subject: [PATCH 02/11] Version 1.71 WIP + fixed minor typo --- docs/CHANGELOG.txt | 8 ++++++++ examples/README.txt | 4 ++-- imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_widgets.cpp | 2 +- misc/fonts/README.txt | 2 +- 9 files changed, 19 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index cafaa6bb..9deed680 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -28,6 +28,14 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.71 (In Progress) +----------------------------------------------------------------------- + +Breaking Changes: + +Other Changes: + ----------------------------------------------------------------------- VERSION 1.70 (Released 2019-05-06) diff --git a/examples/README.txt b/examples/README.txt index 0be7ff6a..82d39ef1 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -1,5 +1,5 @@ ----------------------------------------------------------------------- - dear imgui, v1.70 + dear imgui, v1.71 WIP ----------------------------------------------------------------------- examples/README.txt (This is the README file for the examples/ folder. See docs/ for more documentation) @@ -175,7 +175,7 @@ example_empscripten: We provide this to make the Emscripten differences obvious, and have them not pollute all other examples. example_glfw_metal/ - GLFW (Mac) + Vulkan example. + GLFW (Mac) + Metal example. = main.mm + imgui_impl_glfw.cpp + imgui_impl_metal.mm. example_glfw_opengl2/ diff --git a/imgui.cpp b/imgui.cpp index 0bcaee50..1e6c8a3f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.70 +// dear imgui, v1.71 WIP // (main code and documentation) // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. diff --git a/imgui.h b/imgui.h index 423ba3ac..aafcb3a6 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.70 +// dear imgui, v1.71 WIP // (headers) // See imgui.cpp file for documentation. @@ -46,8 +46,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.70" -#define IMGUI_VERSION_NUM 17000 +#define IMGUI_VERSION "1.71" +#define IMGUI_VERSION_NUM 17001 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) // Define attributes of all API symbols declarations (e.g. for DLL under Windows) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 62196c64..1f01cc4d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.70 +// dear imgui, v1.71 WIP // (demo code) // Message to the person tempted to delete this file when integrating Dear ImGui into their code base: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 63d99a29..467555cf 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.70 +// dear imgui, v1.71 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index cc98c20b..7e91b5fc 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.70 +// dear imgui, v1.71 WIP // (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! diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 5b3ea581..42b28e09 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.70 +// dear imgui, v1.71 WIP // (widgets code) /* diff --git a/misc/fonts/README.txt b/misc/fonts/README.txt index 5c475f2f..0fcc6c79 100644 --- a/misc/fonts/README.txt +++ b/misc/fonts/README.txt @@ -1,4 +1,4 @@ -dear imgui, v1.70 +dear imgui, v1.71 WIP (Font Readme) --------------------------------------- From b7c2759f957dbcc6e48b6f12d59aeffb78ea0be7 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 9 May 2019 12:10:36 +0200 Subject: [PATCH 03/11] Columns: Fixed Separator from creating an extraneous draw command. Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 31 ++++++++++++++++++++++++++----- imgui_internal.h | 5 ++++- imgui_widgets.cpp | 12 ++++++------ 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9deed680..8a137d4e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,8 @@ HOW TO UPDATE? Breaking Changes: Other Changes: +- Columns: Fixed Separator from creating an extraneous draw command. (#125) +- Columns: Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 1e6c8a3f..1045ddd6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8400,13 +8400,13 @@ void ImGui::NextColumn() { // New column (columns 1+ cancels out IndentX) window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + g.Style.ItemSpacing.x; - window->DrawList->ChannelsSetCurrent(columns->Current); + window->DrawList->ChannelsSetCurrent(columns->Current + 1); } else { // New row/line window->DC.ColumnsOffset.x = 0.0f; - window->DrawList->ChannelsSetCurrent(0); + window->DrawList->ChannelsSetCurrent(1); columns->Current = 0; columns->LineMinY = columns->LineMaxY; } @@ -8415,7 +8415,7 @@ void ImGui::NextColumn() window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f); window->DC.CurrentLineTextBaseOffset = 0.0f; - PushColumnClipRect(); + PushColumnClipRect(columns->Current); PushItemWidth(GetColumnWidth() * 0.65f); // FIXME-COLUMNS: Move on columns setup } @@ -8543,6 +8543,25 @@ void ImGui::PushColumnClipRect(int column_index) PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false); } +// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns) +void ImGui::PushColumnsBackground() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiColumns* columns = window->DC.CurrentColumns; + window->DrawList->ChannelsSetCurrent(0); + int cmd_size = window->DrawList->CmdBuffer.Size; + PushClipRect(columns->BackupClipRect.Min, columns->BackupClipRect.Max, false); + IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd +} + +void ImGui::PopColumnsBackground() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiColumns* columns = window->DC.CurrentColumns; + window->DrawList->ChannelsSetCurrent(columns->Current + 1); + PopClipRect(); +} + ImGuiColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id) { // We have few columns per window so for now we don't need bother much with turning this into a faster lookup. @@ -8593,6 +8612,7 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f); columns->BackupCursorPosY = window->DC.CursorPos.y; columns->BackupCursorMaxPosX = window->DC.CursorMaxPos.x; + columns->BackupClipRect = window->ClipRect; columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; window->DC.ColumnsOffset.x = 0.0f; window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); @@ -8626,8 +8646,9 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag if (columns->Count > 1) { - window->DrawList->ChannelsSplit(columns->Count); - PushColumnClipRect(); + window->DrawList->ChannelsSplit(1 + columns->Count); + window->DrawList->ChannelsSetCurrent(1); + PushColumnClipRect(0); } PushItemWidth(GetColumnWidth() * 0.65f); } diff --git a/imgui_internal.h b/imgui_internal.h index 7e91b5fc..a56471db 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -683,6 +683,7 @@ struct ImGuiColumns float LineMinY, LineMaxY; float BackupCursorPosY; // Backup of CursorPos at the time of BeginColumns() float BackupCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns() + ImRect BackupClipRect; ImVector Columns; ImGuiColumns() { Clear(); } @@ -1502,7 +1503,9 @@ namespace ImGui // New Columns API (FIXME-WIP) IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). IMGUI_API void EndColumns(); // close columns - IMGUI_API void PushColumnClipRect(int column_index = -1); + IMGUI_API void PushColumnClipRect(int column_index); + IMGUI_API void PushColumnsBackground(); + IMGUI_API void PopColumnsBackground(); IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count); IMGUI_API ImGuiColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 42b28e09..df9a7d87 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1216,7 +1216,7 @@ void ImGui::Separator() // Horizontal Separator if (window->DC.CurrentColumns) - PopClipRect(); + PushColumnsBackground(); float x1 = window->Pos.x; float x2 = window->Pos.x + window->Size.x; @@ -1228,7 +1228,7 @@ void ImGui::Separator() if (!ItemAdd(bb, 0)) { if (window->DC.CurrentColumns) - PushColumnClipRect(); + PopColumnsBackground(); return; } @@ -1239,7 +1239,7 @@ void ImGui::Separator() if (window->DC.CurrentColumns) { - PushColumnClipRect(); + PopColumnsBackground(); window->DC.CurrentColumns->LineMinY = window->DC.CursorPos.y; } } @@ -5311,7 +5311,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl const ImGuiStyle& style = g.Style; if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns) // FIXME-OPT: Avoid if vertically clipped. - PopClipRect(); + PushColumnsBackground(); ImGuiID id = window->GetID(label); ImVec2 label_size = CalcTextSize(label, NULL, true); @@ -5355,7 +5355,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (!item_add) { if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns) - PushColumnClipRect(); + PopColumnsBackground(); return false; } @@ -5401,7 +5401,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns) { - PushColumnClipRect(); + PopColumnsBackground(); bb.Max.x -= (GetContentRegionMax().x - max_x); } From a4d0b0efa49848bd1b54167ba4c57b95393aca2b Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 9 May 2019 12:55:01 +0200 Subject: [PATCH 04/11] Internal: Refactored Separator into SeparatorEx(), exposed ImGuiSeparatorFlags_SpanAllColumns in imgui_internal.h and support without. (#759) + misc comments --- docs/TODO.txt | 4 +- imgui.cpp | 3 +- imgui_internal.h | 5 ++- imgui_widgets.cpp | 94 +++++++++++++++++++++++++---------------------- 4 files changed, 58 insertions(+), 48 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 4c89c8e3..97594ba4 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -133,7 +133,9 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - clipper: ability to disable the clipping through a simple flag/bool. - clipper: ability to run without knowing full count in advance. - - splitter/separator: formalize the splitter idiom into an official api (we want to handle n-way split) (#319) + - separator: expose flags (#759) + - separator: width, thickness, centering (#1643) + - splitter: formalize the splitter idiom into an official api (we want to handle n-way split) (#319) - dock: merge docking branch (#2109) - dock: dock out from a collapsing header? would work nicely but need emitting window to keep submitting the code. diff --git a/imgui.cpp b/imgui.cpp index 1045ddd6..779ea09e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5445,7 +5445,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->InnerMainRect.Max.x = window->Pos.x + window->Size.x - ImMax(window->ScrollbarSizes.x, window->WindowBorderSize); window->InnerMainRect.Max.y = window->Pos.y + window->Size.y - ImMax(window->ScrollbarSizes.y, window->WindowBorderSize); - // Inner clipping rectangle + // Inner clipping rectangle will extend a little bit outside the work region. + // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space. // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); diff --git a/imgui_internal.h b/imgui_internal.h index a56471db..01f805ba 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -354,7 +354,8 @@ enum ImGuiSeparatorFlags_ { ImGuiSeparatorFlags_None = 0, ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar - ImGuiSeparatorFlags_Vertical = 1 << 1 + ImGuiSeparatorFlags_Vertical = 1 << 1, + ImGuiSeparatorFlags_SpanAllColumns = 1 << 2 }; // Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin(). @@ -1551,7 +1552,7 @@ namespace ImGui IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags); IMGUI_API void Scrollbar(ImGuiAxis axis); IMGUI_API ImGuiID GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis); - IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. + IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); // Widgets low-level behaviors IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index df9a7d87..2d505f56 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1146,8 +1146,8 @@ void ImGui::Bullet() // - Dummy() // - NewLine() // - AlignTextToFramePadding() +// - SeparatorEx() [Internal] // - Separator() -// - VerticalSeparator() [Internal] // - SplitterBehavior() [Internal] //------------------------------------------------------------------------- @@ -1198,69 +1198,75 @@ void ImGui::AlignTextToFramePadding() } // Horizontal/vertical separating line -void ImGui::Separator() +void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; - ImGuiContext& g = *GImGui; - // Those flags should eventually be overrideable by the user - ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; + ImGuiContext& g = *GImGui; IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected + if (flags & ImGuiSeparatorFlags_Vertical) { - VerticalSeparator(); - return; - } - - // Horizontal Separator - if (window->DC.CurrentColumns) - PushColumnsBackground(); - - float x1 = window->Pos.x; - float x2 = window->Pos.x + window->Size.x; - if (!window->DC.GroupStack.empty()) - x1 += window->DC.Indent.x; + // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. + float y1 = window->DC.CursorPos.y; + float y2 = window->DC.CursorPos.y + window->DC.CurrentLineSize.y; + const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + 1.0f, y2)); + ItemSize(ImVec2(1.0f, 0.0f)); + if (!ItemAdd(bb, 0)) + return; - const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y+1.0f)); - ItemSize(ImVec2(0.0f, 1.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit - if (!ItemAdd(bb, 0)) - { - if (window->DC.CurrentColumns) - PopColumnsBackground(); - return; + // Draw + window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator)); + if (g.LogEnabled) + LogText(" |"); } + else if (flags & ImGuiSeparatorFlags_Horizontal) + { + // Horizontal Separator + float x1 = window->Pos.x; + float x2 = window->Pos.x + window->Size.x; + if (!window->DC.GroupStack.empty()) + x1 += window->DC.Indent.x; - window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x,bb.Min.y), GetColorU32(ImGuiCol_Separator)); + ImGuiColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL; + if (columns) + PushColumnsBackground(); - if (g.LogEnabled) - LogRenderedText(&bb.Min, "--------------------------------"); + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + 1.0f)); + ItemSize(ImVec2(0.0f, 1.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit + if (!ItemAdd(bb, 0)) + { + if (columns) + PopColumnsBackground(); + return; + } - if (window->DC.CurrentColumns) - { - PopColumnsBackground(); - window->DC.CurrentColumns->LineMinY = window->DC.CursorPos.y; + // Draw + window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator)); + if (g.LogEnabled) + LogRenderedText(&bb.Min, "--------------------------------"); + + if (columns) + { + PopColumnsBackground(); + columns->LineMinY = window->DC.CursorPos.y; + } } } -void ImGui::VerticalSeparator() +void ImGui::Separator() { - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return; ImGuiContext& g = *GImGui; - - float y1 = window->DC.CursorPos.y; - float y2 = window->DC.CursorPos.y + window->DC.CurrentLineSize.y; - const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + 1.0f, y2)); - ItemSize(ImVec2(1.0f, 0.0f)); - if (!ItemAdd(bb, 0)) + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) return; - window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator)); - if (g.LogEnabled) - LogText(" |"); + // Those flags should eventually be overridable by the user + ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; + flags |= ImGuiSeparatorFlags_SpanAllColumns; + SeparatorEx(flags); } // Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise. From e29176df530c885a0c541f3691be76771fd222be Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 9 May 2019 12:56:03 +0200 Subject: [PATCH 05/11] Internals: Columns: Renamed fields. Comments and tweak. Moved a demo block. --- imgui.cpp | 45 ++++++++++++++++++++++------------------- imgui.h | 2 +- imgui_demo.cpp | 52 ++++++++++++++++++++++++------------------------ imgui_internal.h | 14 ++++++------- 4 files changed, 58 insertions(+), 55 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 779ea09e..a75829ef 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1140,7 +1140,7 @@ ImGuiStyle::ImGuiStyle() ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). - ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns + ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar @@ -5452,6 +5452,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); + // Setup drawing context // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; @@ -8434,12 +8435,12 @@ int ImGui::GetColumnsCount() static float OffsetNormToPixels(const ImGuiColumns* columns, float offset_norm) { - return offset_norm * (columns->MaxX - columns->MinX); + return offset_norm * (columns->OffMaxX - columns->OffMinX); } static float PixelsToOffsetNorm(const ImGuiColumns* columns, float offset) { - return offset / (columns->MaxX - columns->MinX); + return offset / (columns->OffMaxX - columns->OffMinX); } static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; @@ -8472,7 +8473,7 @@ float ImGui::GetColumnOffset(int column_index) IM_ASSERT(column_index < columns->Columns.Size); const float t = columns->Columns[column_index].OffsetNorm; - const float x_offset = ImLerp(columns->MinX, columns->MaxX, t); + const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); return x_offset; } @@ -8515,8 +8516,8 @@ void ImGui::SetColumnOffset(int column_index, float offset) const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow)) - offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); - columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX); + offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); + columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->OffMinX); if (preserve_width) SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); @@ -8551,7 +8552,7 @@ void ImGui::PushColumnsBackground() ImGuiColumns* columns = window->DC.CurrentColumns; window->DrawList->ChannelsSetCurrent(0); int cmd_size = window->DrawList->CmdBuffer.Size; - PushClipRect(columns->BackupClipRect.Min, columns->BackupClipRect.Max, false); + PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false); IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd } @@ -8597,9 +8598,8 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag IM_ASSERT(columns_count >= 1); IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported - ImGuiID id = GetColumnsID(str_id, columns_count); - // Acquire storage for the columns set + ImGuiID id = GetColumnsID(str_id, columns_count); ImGuiColumns* columns = FindOrCreateColumns(window, id); IM_ASSERT(columns->ID == id); columns->Current = 0; @@ -8609,11 +8609,11 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag // Set state for first column const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x); - columns->MinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range - columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f); - columns->BackupCursorPosY = window->DC.CursorPos.y; - columns->BackupCursorMaxPosX = window->DC.CursorMaxPos.x; - columns->BackupClipRect = window->ClipRect; + columns->OffMinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range + columns->OffMaxX = ImMax(content_region_width - window->Scroll.x, columns->OffMinX + 1.0f); + columns->HostCursorPosY = window->DC.CursorPos.y; + columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; + columns->HostClipRect = window->ClipRect; columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; window->DC.ColumnsOffset.x = 0.0f; window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); @@ -8622,7 +8622,7 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) columns->Columns.resize(0); - // Initialize defaults + // Initialize default widths columns->IsFirstFrame = (columns->Columns.Size == 0); if (columns->Columns.Size == 0) { @@ -8668,17 +8668,19 @@ void ImGui::EndColumns() window->DrawList->ChannelsMerge(); } + const ImGuiColumnsFlags flags = columns->Flags; columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); window->DC.CursorPos.y = columns->LineMaxY; - if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize)) - window->DC.CursorMaxPos.x = columns->BackupCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent + if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize)) + window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent // Draw columns borders and handle resize + // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy bool is_being_resized = false; - if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) + if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) { // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. - const float y1 = ImMax(columns->BackupCursorPosY, window->ClipRect.Min.y); + const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y); const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y); int dragging_column = -1; for (int n = 1; n < columns->Count; n++) @@ -8693,7 +8695,7 @@ void ImGui::EndColumns() continue; bool hovered = false, held = false; - if (!(columns->Flags & ImGuiColumnsFlags_NoResize)) + if (!(flags & ImGuiColumnsFlags_NoResize)) { ButtonBehavior(column_hit_rect, column_id, &hovered, &held); if (hovered || held) @@ -8745,6 +8747,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) BeginColumns(id, columns_count, flags); } + //----------------------------------------------------------------------------- // [SECTION] DRAG AND DROP //----------------------------------------------------------------------------- @@ -9692,7 +9695,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) { if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) return; - ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX); + ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); for (int column_n = 0; column_n < columns->Columns.Size; column_n++) ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm)); ImGui::TreePop(); diff --git a/imgui.h b/imgui.h index aafcb3a6..0d46ec5d 100644 --- a/imgui.h +++ b/imgui.h @@ -1293,7 +1293,7 @@ struct ImGuiStyle ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). - float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. + float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar. float ScrollbarRounding; // Radius of grab corners for scrollbar. float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1f01cc4d..e0d9c761 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2426,6 +2426,32 @@ static void ShowDemoWindowColumns() ImGui::TreePop(); } + if (ImGui::TreeNode("Borders")) + { + // NB: Future columns API should allow automatic horizontal borders. + static bool h_borders = true; + static bool v_borders = true; + ImGui::Checkbox("horizontal", &h_borders); + ImGui::SameLine(); + ImGui::Checkbox("vertical", &v_borders); + ImGui::Columns(4, NULL, v_borders); + for (int i = 0; i < 4 * 3; i++) + { + if (h_borders && ImGui::GetColumnIndex() == 0) + ImGui::Separator(); + ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); + ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); + ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); + ImGui::Text("Long text that is likely to clip"); + ImGui::Button("Button", ImVec2(-1.0f, 0.0f)); + ImGui::NextColumn(); + } + ImGui::Columns(1); + if (h_borders) + ImGui::Separator(); + ImGui::TreePop(); + } + // Create multiple items in a same cell before switching to next column if (ImGui::TreeNode("Mixed items")) { @@ -2472,32 +2498,6 @@ static void ShowDemoWindowColumns() ImGui::TreePop(); } - if (ImGui::TreeNode("Borders")) - { - // NB: Future columns API should allow automatic horizontal borders. - static bool h_borders = true; - static bool v_borders = true; - ImGui::Checkbox("horizontal", &h_borders); - ImGui::SameLine(); - ImGui::Checkbox("vertical", &v_borders); - ImGui::Columns(4, NULL, v_borders); - for (int i = 0; i < 4*3; i++) - { - if (h_borders && ImGui::GetColumnIndex() == 0) - ImGui::Separator(); - ImGui::Text("%c%c%c", 'a'+i, 'a'+i, 'a'+i); - ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); - ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); - ImGui::Text("Long text that is likely to clip"); - ImGui::Button("Button", ImVec2(-1.0f, 0.0f)); - ImGui::NextColumn(); - } - ImGui::Columns(1); - if (h_borders) - ImGui::Separator(); - ImGui::TreePop(); - } - // Scrolling columns /* if (ImGui::TreeNode("Vertical Scrolling")) diff --git a/imgui_internal.h b/imgui_internal.h index 01f805ba..b8bd9a6c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -680,11 +680,11 @@ struct ImGuiColumns bool IsBeingResized; int Current; int Count; - float MinX, MaxX; + float OffMinX, OffMaxX; // Offsets from HostWorkRect.Min.x float LineMinY, LineMaxY; - float BackupCursorPosY; // Backup of CursorPos at the time of BeginColumns() - float BackupCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns() - ImRect BackupClipRect; + float HostCursorPosY; // Backup of CursorPos at the time of BeginColumns() + float HostCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns() + ImRect HostClipRect; // Backup of ClipRect at the time of BeginColumns() ImVector Columns; ImGuiColumns() { Clear(); } @@ -696,10 +696,10 @@ struct ImGuiColumns IsBeingResized = false; Current = 0; Count = 1; - MinX = MaxX = 0.0f; + OffMinX = OffMaxX = 0.0f; LineMinY = LineMaxY = 0.0f; - BackupCursorPosY = 0.0f; - BackupCursorMaxPosX = 0.0f; + HostCursorPosY = 0.0f; + HostCursorMaxPosX = 0.0f; Columns.clear(); } }; From 9534ef9b26b1a3240c31f7bd643d8ebfdef01484 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 9 May 2019 17:52:56 +0200 Subject: [PATCH 06/11] Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change (c5d83d8a). It's not incorrect but it breaks existing some layout patterns. Will return back to it when we expose Separator flags. --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8a137d4e..f0d1cf05 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -37,6 +37,8 @@ Breaking Changes: Other Changes: - Columns: Fixed Separator from creating an extraneous draw command. (#125) - Columns: Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125) +- Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect + but it breaks existing some layout patterns. Will return back to it when we expose Separator flags. ----------------------------------------------------------------------- diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2d505f56..2d00300e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1207,13 +1207,15 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) ImGuiContext& g = *GImGui; IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected + float thickness_draw = 1.0f; + float thickness_layout = 0.0f; if (flags & ImGuiSeparatorFlags_Vertical) { // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. float y1 = window->DC.CursorPos.y; float y2 = window->DC.CursorPos.y + window->DC.CurrentLineSize.y; - const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + 1.0f, y2)); - ItemSize(ImVec2(1.0f, 0.0f)); + const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness_draw, y2)); + ItemSize(ImVec2(thickness_layout, 0.0f)); if (!ItemAdd(bb, 0)) return; @@ -1234,8 +1236,9 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) if (columns) PushColumnsBackground(); - const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + 1.0f)); - ItemSize(ImVec2(0.0f, 1.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit + // We don't provide our width to the layout so that it doesn't get feed back into AutoFit + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness_draw)); + ItemSize(ImVec2(0.0f, thickness_layout)); if (!ItemAdd(bb, 0)) { if (columns) From 37174c85e270672526baf526f725e915029b0d77 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 9 May 2019 19:05:36 +0200 Subject: [PATCH 07/11] Internal: Scrollbar: Extracted scrollbar code for other uses (eg. table v2 scrolling without using a child window). --- imgui_internal.h | 5 +- imgui_widgets.cpp | 143 ++++++++++++++++++++++++---------------------- 2 files changed, 79 insertions(+), 69 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index b8bd9a6c..fd579a37 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -956,7 +956,7 @@ struct ImGuiContext bool DragCurrentAccumDirty; float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio - ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? + float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? int TooltipOverrideCount; ImVector PrivateClipboard; // If no custom clipboard handler is defined @@ -1092,7 +1092,7 @@ struct ImGuiContext DragCurrentAccumDirty = false; DragCurrentAccum = 0.0f; DragSpeedDefaultRatio = 1.0f / 100.0f; - ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); + ScrollbarClickDeltaToGrabCenter = 0.0f; TooltipOverrideCount = 0; MultiSelectScopeId = 0; @@ -1551,6 +1551,7 @@ namespace ImGui IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags); IMGUI_API void Scrollbar(ImGuiAxis axis); + IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float avail_v, float contents_v, ImDrawCornerFlags rounding_corners); IMGUI_API ImGuiID GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis); IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2d00300e..2b4368bc 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -380,6 +380,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // - ArrowButton() // - CloseButton() [Internal] // - CollapseButton() [Internal] +// - ScrollbarEx() [Internal] // - Scrollbar() [Internal] // - Image() // - ImageButton() @@ -777,125 +778,133 @@ ImGuiID ImGui::GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis) // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. -void ImGui::Scrollbar(ImGuiAxis axis) +// Still, the code should probably be made simpler.. +bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float size_avail_v, float size_contents_v, ImDrawCornerFlags rounding_corners) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; - const bool horizontal = (axis == ImGuiAxis_X); - const ImGuiStyle& style = g.Style; - const ImGuiID id = GetScrollbarID(window, axis); - KeepAliveID(id); - - // Render background - bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX); - float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f; - const ImRect host_rect = window->Rect(); - const float border_size = window->WindowBorderSize; - ImRect bb = horizontal - ? ImRect(host_rect.Min.x + border_size, host_rect.Max.y - style.ScrollbarSize, host_rect.Max.x - other_scrollbar_size_w - border_size, host_rect.Max.y - border_size) - : ImRect(host_rect.Max.x - style.ScrollbarSize, host_rect.Min.y + border_size, host_rect.Max.x - border_size, host_rect.Max.y - other_scrollbar_size_w - border_size); - bb.Min.x = ImMax(host_rect.Min.x, bb.Min.x); // Handle case where the host rectangle is smaller than the scrollbar - bb.Min.y = ImMax(host_rect.Min.y, bb.Min.y); - if (!horizontal) - bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); // FIXME: InnerRect? - - const float bb_width = bb.GetWidth(); - const float bb_height = bb.GetHeight(); - if (bb_width <= 0.0f || bb_height <= 0.0f) - return; + const float bb_frame_width = bb_frame.GetWidth(); + const float bb_frame_height = bb_frame.GetHeight(); + if (bb_frame_width <= 0.0f || bb_frame_height <= 0.0f) + return false; // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the resize grab) float alpha = 1.0f; - if ((axis == ImGuiAxis_Y) && bb_height < g.FontSize + g.Style.FramePadding.y * 2.0f) - { - alpha = ImSaturate((bb_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f)); - if (alpha <= 0.0f) - return; - } + if ((axis == ImGuiAxis_Y) && bb_frame_height < g.FontSize + g.Style.FramePadding.y * 2.0f) + alpha = ImSaturate((bb_frame_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f)); + if (alpha <= 0.0f) + return false; + + const ImGuiStyle& style = g.Style; const bool allow_interaction = (alpha >= 1.0f); + const bool horizontal = (axis == ImGuiAxis_X); - int window_rounding_corners; - if (horizontal) - window_rounding_corners = ImDrawCornerFlags_BotLeft | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight); - else - window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0) | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight); - window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, window_rounding_corners); - bb.Expand(ImVec2(-ImClamp((float)(int)((bb_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb_height - 2.0f) * 0.5f), 0.0f, 3.0f))); + ImRect bb = bb_frame; + bb.Expand(ImVec2(-ImClamp((float)(int)((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f))); // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar) - float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight(); - float scroll_v = horizontal ? window->Scroll.x : window->Scroll.y; - float win_size_avail_v = (horizontal ? window->SizeFull.x : window->SizeFull.y) - other_scrollbar_size_w; - float win_size_contents_v = horizontal ? window->SizeContents.x : window->SizeContents.y; + const float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight(); // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount) // But we maintain a minimum size in pixel to allow for the user to still aim inside. - IM_ASSERT(ImMax(win_size_contents_v, win_size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers. - const float win_size_v = ImMax(ImMax(win_size_contents_v, win_size_avail_v), 1.0f); - const float grab_h_pixels = ImClamp(scrollbar_size_v * (win_size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v); + IM_ASSERT(ImMax(size_contents_v, size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers. + const float win_size_v = ImMax(ImMax(size_contents_v, size_avail_v), 1.0f); + const float grab_h_pixels = ImClamp(scrollbar_size_v * (size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v); const float grab_h_norm = grab_h_pixels / scrollbar_size_v; // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). bool held = false; bool hovered = false; - const bool previously_held = (g.ActiveId == id); ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); - float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v); - float scroll_ratio = ImSaturate(scroll_v / scroll_max); + float scroll_max = ImMax(1.0f, size_contents_v - size_avail_v); + float scroll_ratio = ImSaturate(*p_scroll_v / scroll_max); float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; if (held && allow_interaction && grab_h_norm < 1.0f) { float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y; float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y; - float* click_delta_to_grab_center_v = horizontal ? &g.ScrollbarClickDeltaToGrabCenter.x : &g.ScrollbarClickDeltaToGrabCenter.y; // Click position in scrollbar normalized space (0.0f->1.0f) const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v); SetHoveredID(id); bool seek_absolute = false; - if (!previously_held) + if (g.ActiveIdIsJustActivated) { // On initial click calculate the distance between mouse and the center of the grab - if (clicked_v_norm >= grab_v_norm && clicked_v_norm <= grab_v_norm + grab_h_norm) - { - *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f; - } + seek_absolute = (clicked_v_norm < grab_v_norm || clicked_v_norm > grab_v_norm + grab_h_norm); + if (seek_absolute) + g.ScrollbarClickDeltaToGrabCenter = 0.0f; else - { - seek_absolute = true; - *click_delta_to_grab_center_v = 0.0f; - } + g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; } // Apply scroll // It is ok to modify Scroll here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position - const float scroll_v_norm = ImSaturate((clicked_v_norm - *click_delta_to_grab_center_v - grab_h_norm*0.5f) / (1.0f - grab_h_norm)); - scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v)); - if (horizontal) - window->Scroll.x = scroll_v; - else - window->Scroll.y = scroll_v; + const float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm)); + *p_scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v)); // Update values for rendering - scroll_ratio = ImSaturate(scroll_v / scroll_max); + scroll_ratio = ImSaturate(*p_scroll_v / scroll_max); grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; // Update distance to grab now that we have seeked and saturated if (seek_absolute) - *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f; + g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; } - // Render grab + // Render + window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, rounding_corners); const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); ImRect grab_rect; if (horizontal) - grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, host_rect.Max.x), bb.Max.y); + grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y); else - grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImMin(ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels, host_rect.Max.y)); + grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels); window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding); + + return held; +} + +void ImGui::Scrollbar(ImGuiAxis axis) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const bool horizontal = (axis == ImGuiAxis_X); + const ImGuiStyle& style = g.Style; + const ImGuiID id = GetScrollbarID(window, axis); + KeepAliveID(id); + + // Calculate our bounding box (FIXME: This is messy, should be made simpler using e.g. InnerRect/WorkRect data). + const float other_scrollbar_size = window->ScrollbarSizes[axis]; + const ImRect win_rect = window->Rect(); + const float border_size = window->WindowBorderSize; + ImRect bb = horizontal + ? ImRect(win_rect.Min.x + border_size, win_rect.Max.y - style.ScrollbarSize, win_rect.Max.x - other_scrollbar_size - border_size, win_rect.Max.y - border_size) + : ImRect(win_rect.Max.x - style.ScrollbarSize, win_rect.Min.y + border_size, win_rect.Max.x - border_size, win_rect.Max.y - other_scrollbar_size - border_size); + bb.Min.x = ImMax(win_rect.Min.x, bb.Min.x); // Handle case where the host rectangle is smaller than the scrollbar + bb.Min.y = ImMax(win_rect.Min.y, bb.Min.y); + if (!horizontal) + bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); // FIXME: InnerRect? + + // Select rounding + ImDrawCornerFlags rounding_corners; + if (horizontal) + rounding_corners = ImDrawCornerFlags_BotLeft; + else + rounding_corners = ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0; + if (other_scrollbar_size <= 0.0f) + rounding_corners |= ImDrawCornerFlags_BotRight; + + if (horizontal) + ScrollbarEx(bb, id, axis, &window->Scroll.x, window->SizeFull.x - other_scrollbar_size, window->SizeContents.x, rounding_corners); + else + ScrollbarEx(bb, id, axis, &window->Scroll.y, window->SizeFull.y - other_scrollbar_size, window->SizeContents.y, rounding_corners); } void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) From 39eeda0227892e5d616b622fe57f53cc9e824dc6 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 9 May 2019 19:30:13 +0200 Subject: [PATCH 08/11] Internal: Scrollbar: Further sane simplification (using InnerMainRect instead of duplicating calculations). --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 41 ++++++++++++++++------------------------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f0d1cf05..366b695b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -39,6 +39,7 @@ Other Changes: - Columns: Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125) - Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect but it breaks existing some layout patterns. Will return back to it when we expose Separator flags. +- Scrollbar: Very minor bounding box adjustment to cope with various border size. ----------------------------------------------------------------------- diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2b4368bc..e0ebdbc2 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -875,36 +875,27 @@ void ImGui::Scrollbar(ImGuiAxis axis) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - const bool horizontal = (axis == ImGuiAxis_X); - const ImGuiStyle& style = g.Style; const ImGuiID id = GetScrollbarID(window, axis); KeepAliveID(id); - // Calculate our bounding box (FIXME: This is messy, should be made simpler using e.g. InnerRect/WorkRect data). + // Calculate scrollbar bounding box + const ImRect outer_rect = window->Rect(); const float other_scrollbar_size = window->ScrollbarSizes[axis]; - const ImRect win_rect = window->Rect(); - const float border_size = window->WindowBorderSize; - ImRect bb = horizontal - ? ImRect(win_rect.Min.x + border_size, win_rect.Max.y - style.ScrollbarSize, win_rect.Max.x - other_scrollbar_size - border_size, win_rect.Max.y - border_size) - : ImRect(win_rect.Max.x - style.ScrollbarSize, win_rect.Min.y + border_size, win_rect.Max.x - border_size, win_rect.Max.y - other_scrollbar_size - border_size); - bb.Min.x = ImMax(win_rect.Min.x, bb.Min.x); // Handle case where the host rectangle is smaller than the scrollbar - bb.Min.y = ImMax(win_rect.Min.y, bb.Min.y); - if (!horizontal) - bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); // FIXME: InnerRect? - - // Select rounding - ImDrawCornerFlags rounding_corners; - if (horizontal) - rounding_corners = ImDrawCornerFlags_BotLeft; - else - rounding_corners = ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0; - if (other_scrollbar_size <= 0.0f) - rounding_corners |= ImDrawCornerFlags_BotRight; - - if (horizontal) - ScrollbarEx(bb, id, axis, &window->Scroll.x, window->SizeFull.x - other_scrollbar_size, window->SizeContents.x, rounding_corners); + ImDrawCornerFlags rounding_corners = (other_scrollbar_size <= 0.0f) ? ImDrawCornerFlags_BotRight : 0; + ImRect bb; + if (axis == ImGuiAxis_X) + { + bb.Min = ImVec2(window->InnerMainRect.Min.x, window->InnerMainRect.Max.y); + bb.Max = ImVec2(window->InnerMainRect.Max.x, outer_rect.Max.y - window->WindowBorderSize); + rounding_corners |= ImDrawCornerFlags_BotLeft; + } else - ScrollbarEx(bb, id, axis, &window->Scroll.y, window->SizeFull.y - other_scrollbar_size, window->SizeContents.y, rounding_corners); + { + bb.Min = ImVec2(window->InnerMainRect.Max.x, window->InnerMainRect.Min.y); + bb.Max = ImVec2(outer_rect.Max.x - window->WindowBorderSize, window->InnerMainRect.Max.y); + rounding_corners |= ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0; + } + ScrollbarEx(bb, id, axis, &window->Scroll[axis], window->SizeFull[axis] - other_scrollbar_size, window->SizeContents[axis], rounding_corners); } void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) From b50c61c961498e15b5a4c22c7e7e10df13a64e77 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 10 May 2019 22:30:33 +0200 Subject: [PATCH 09/11] Internal: Begin: Update rectangles before Scrollbar() which now uses them. Fixes 39eeda0. --- imgui.cpp | 66 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a75829ef..7f433ee5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5307,6 +5307,40 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) else window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f); + // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars. + window->SizeFullAtLastBegin = window->SizeFull; + + // UPDATE RECTANGLES + + // Update various regions. Variables they depends on are set above in this function. + // FIXME: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. + // NB: WindowBorderSize is included in WindowPadding _and_ ScrollbarSizes so we need to cancel one out. + window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; + window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); + window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x + ImMin(window->ScrollbarSizes.x, window->WindowBorderSize))); + window->ContentsRegionRect.Max.y = window->Pos.y - window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y + ImMin(window->ScrollbarSizes.y, window->WindowBorderSize))); + + // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() + window->OuterRectClipped = window->Rect(); + window->OuterRectClipped.ClipWith(window->ClipRect); + + // Inner rectangle + // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame + // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. + const ImRect title_bar_rect = window->TitleBarRect(); + window->InnerMainRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize; + window->InnerMainRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); + window->InnerMainRect.Max.x = window->Pos.x + window->Size.x - ImMax(window->ScrollbarSizes.x, window->WindowBorderSize); + window->InnerMainRect.Max.y = window->Pos.y + window->Size.y - ImMax(window->ScrollbarSizes.y, window->WindowBorderSize); + + // Inner clipping rectangle will extend a little bit outside the work region. + // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space. + // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. + window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); + window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); + window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); + window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); + // DRAWING // Setup draw list and outer clipping rectangle @@ -5342,7 +5376,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const float window_border_size = window->WindowBorderSize; const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); - const ImRect title_bar_rect = window->TitleBarRect(); if (window->Collapsed) { // Title bar only @@ -5422,37 +5455,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); } - // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars. - window->SizeFullAtLastBegin = window->SizeFull; - - // Update various regions. Variables they depends on are set above in this function. - // FIXME: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. - // NB: WindowBorderSize is included in WindowPadding _and_ ScrollbarSizes so we need to cancel one out. - window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; - window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); - window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x + ImMin(window->ScrollbarSizes.x, window->WindowBorderSize))); - window->ContentsRegionRect.Max.y = window->Pos.y - window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y + ImMin(window->ScrollbarSizes.y, window->WindowBorderSize))); - - // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() - window->OuterRectClipped = window->Rect(); - window->OuterRectClipped.ClipWith(window->ClipRect); - - // Inner rectangle - // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame - // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. - window->InnerMainRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize; - window->InnerMainRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); - window->InnerMainRect.Max.x = window->Pos.x + window->Size.x - ImMax(window->ScrollbarSizes.x, window->WindowBorderSize); - window->InnerMainRect.Max.y = window->Pos.y + window->Size.y - ImMax(window->ScrollbarSizes.y, window->WindowBorderSize); - - // Inner clipping rectangle will extend a little bit outside the work region. - // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space. - // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. - window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); - window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); - window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); - window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); - // Setup drawing context // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; From 72951a1a85771b721a2011b51a01c6a146c9f1a2 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 10 May 2019 22:38:10 +0200 Subject: [PATCH 10/11] Internal: Extracted some of the Begin code into RenderWindowTitleBarContents(). --- imgui.cpp | 108 +++++++++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7f433ee5..d3ad06fa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1076,7 +1076,8 @@ static int FindWindowFocusIndex(ImGuiWindow* window); static void UpdateMouseInputs(); static void UpdateMouseWheel(); static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); -static void RenderOuterBorders(ImGuiWindow* window); +static void RenderWindowOuterBorders(ImGuiWindow* window); +static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); } @@ -4926,7 +4927,7 @@ static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, cons window->Pos = ImMin(rect.Max - padding, ImMax(window->Pos + size_for_clamping, rect.Min + padding) - size_for_clamping); } -static void ImGui::RenderOuterBorders(ImGuiWindow* window) +static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) { ImGuiContext& g = *GImGui; float rounding = window->WindowRounding; @@ -4963,6 +4964,58 @@ static void ImGui::RenderOuterBorders(ImGuiWindow* window) } } +void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImGuiWindowFlags flags = window->Flags; + + // Close & collapse button are on layer 1 (same as menus) and don't default focus + const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; + window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); + + // Collapse button + if (!(flags & ImGuiWindowFlags_NoCollapse)) + if (CollapseButton(window->GetID("#COLLAPSE"), window->Pos)) + window->WantCollapseToggle = true; // Defer collapsing to next frame as we are too far in the Begin() function + + // Close button + if (p_open != NULL) + { + const float rad = g.FontSize * 0.5f; + if (CloseButton(window->GetID("#CLOSE"), ImVec2(window->Pos.x + window->Size.x - style.FramePadding.x - rad, window->Pos.y + style.FramePadding.y + rad), rad + 1)) + *p_open = false; + } + + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); + window->DC.ItemFlags = item_flags_backup; + + // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker) + // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code.. + const char* UNSAVED_DOCUMENT_MARKER = "*"; + const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f; + const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); + ImRect text_r = title_bar_rect; + float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); + float pad_right = (p_open == NULL) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); + if (style.WindowTitleAlign.x > 0.0f) + pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x); + text_r.Min.x += pad_left; + text_r.Max.x -= pad_right; + ImRect clip_rect = text_r; + clip_rect.Max.x = window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x); // Match the size of CloseButton() + RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect); + if (flags & ImGuiWindowFlags_UnsavedDocument) + { + ImVec2 marker_pos = ImVec2(ImMax(text_r.Min.x, text_r.Min.x + (text_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, text_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f); + ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f)); + RenderTextClipped(marker_pos + off, text_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_rect); + } +} + void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) { window->ParentWindow = parent_window; @@ -4978,7 +5031,7 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags } } -// Push a new ImGui window to add widgets to. +// Push a new Dear ImGui window to add widgets to. // - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. // - Begin/End can be called multiple times during the frame with the same window name to append content. // - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). @@ -5438,7 +5491,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } // Borders - RenderOuterBorders(window); + RenderWindowOuterBorders(window); } // Draw navigation selection/windowing rectangle border @@ -5508,52 +5561,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) - { - // Close & collapse button are on layer 1 (same as menus) and don't default focus - const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; - window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; - window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; - window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); - - // Collapse button - if (!(flags & ImGuiWindowFlags_NoCollapse)) - if (CollapseButton(window->GetID("#COLLAPSE"), window->Pos)) - window->WantCollapseToggle = true; // Defer collapsing to next frame as we are too far in the Begin() function - - // Close button - if (p_open != NULL) - { - const float rad = g.FontSize * 0.5f; - if (CloseButton(window->GetID("#CLOSE"), ImVec2(window->Pos.x + window->Size.x - style.FramePadding.x - rad, window->Pos.y + style.FramePadding.y + rad), rad + 1)) - *p_open = false; - } - - window->DC.NavLayerCurrent = ImGuiNavLayer_Main; - window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); - window->DC.ItemFlags = item_flags_backup; - - // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker) - // FIXME: Refactor text alignment facilities along with RenderText helpers, this is too much code.. - const char* UNSAVED_DOCUMENT_MARKER = "*"; - float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f; - ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); - ImRect text_r = title_bar_rect; - float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); - float pad_right = (p_open == NULL) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); - if (style.WindowTitleAlign.x > 0.0f) - pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x); - text_r.Min.x += pad_left; - text_r.Max.x -= pad_right; - ImRect clip_rect = text_r; - clip_rect.Max.x = window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x); // Match the size of CloseButton() - RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect); - if (flags & ImGuiWindowFlags_UnsavedDocument) - { - ImVec2 marker_pos = ImVec2(ImMax(text_r.Min.x, text_r.Min.x + (text_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, text_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f); - ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f)); - RenderTextClipped(marker_pos + off, text_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_rect); - } - } + RenderWindowTitleBarContents(window, title_bar_rect, name, p_open); // Pressing CTRL+C while holding on a window copy its content to the clipboard // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. From 7c256fbd40f50683908a91e32610f07e243ac7e0 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 10 May 2019 22:45:52 +0200 Subject: [PATCH 11/11] Internal: Extracted some of the Begin code into RenderWindowDecorations(). --- imgui.cpp | 148 +++++++++++++++++++++++++++++------------------------- 1 file changed, 79 insertions(+), 69 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d3ad06fa..d7a75f96 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1077,6 +1077,7 @@ static void UpdateMouseInputs(); static void UpdateMouseWheel(); static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); 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); } @@ -4964,6 +4965,82 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) } } +void ImGui::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) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImGuiWindowFlags flags = window->Flags; + + // Draw window + handle manual resize + // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame. + const float window_rounding = window->WindowRounding; + const float window_border_size = window->WindowBorderSize; + if (window->Collapsed) + { + // Title bar only + float backup_border_size = style.FrameBorderSize; + g.Style.FrameBorderSize = window->WindowBorderSize; + ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); + RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); + g.Style.FrameBorderSize = backup_border_size; + } + else + { + // Window background + if (!(flags & ImGuiWindowFlags_NoBackground)) + { + ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); + float alpha = 1.0f; + if (g.NextWindowData.BgAlphaCond != 0) + alpha = g.NextWindowData.BgAlphaVal; + if (alpha != 1.0f) + bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); + window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); + } + g.NextWindowData.BgAlphaCond = 0; + + // Title bar + if (!(flags & ImGuiWindowFlags_NoTitleBar)) + { + ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); + window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top); + } + + // Menu bar + if (flags & ImGuiWindowFlags_MenuBar) + { + ImRect menu_bar_rect = window->MenuBarRect(); + menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. + window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); + if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) + window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); + } + + // Scrollbars + if (window->ScrollbarX) + Scrollbar(ImGuiAxis_X); + if (window->ScrollbarY) + Scrollbar(ImGuiAxis_Y); + + // Render resize grips (after their input handling so we don't have a frame of latency) + if (!(flags & ImGuiWindowFlags_NoResize)) + { + for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) + { + const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size))); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size))); + window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); + window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]); + } + } + + // Borders + RenderWindowOuterBorders(window); + } +} + void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open) { ImGuiContext& g = *GImGui; @@ -5349,7 +5426,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) int border_held = -1; ImU32 resize_grip_col[4] = { 0 }; const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // 4 - const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); + const float resize_grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); if (!window->Collapsed) UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]); window->ResizeBorderHeld = (signed char)border_held; @@ -5423,76 +5500,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); } - // Draw window + handle manual resize - // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame. - const float window_rounding = window->WindowRounding; - const float window_border_size = window->WindowBorderSize; const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); - if (window->Collapsed) - { - // Title bar only - float backup_border_size = style.FrameBorderSize; - g.Style.FrameBorderSize = window->WindowBorderSize; - ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); - RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); - g.Style.FrameBorderSize = backup_border_size; - } - else - { - // Window background - if (!(flags & ImGuiWindowFlags_NoBackground)) - { - ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); - float alpha = 1.0f; - if (g.NextWindowData.BgAlphaCond != 0) - alpha = g.NextWindowData.BgAlphaVal; - if (alpha != 1.0f) - bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); - window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); - } - g.NextWindowData.BgAlphaCond = 0; - - // Title bar - if (!(flags & ImGuiWindowFlags_NoTitleBar)) - { - ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); - window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top); - } - - // Menu bar - if (flags & ImGuiWindowFlags_MenuBar) - { - ImRect menu_bar_rect = window->MenuBarRect(); - menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. - window->DrawList->AddRectFilled(menu_bar_rect.Min+ImVec2(window_border_size,0), menu_bar_rect.Max-ImVec2(window_border_size,0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); - if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) - window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); - } - - // Scrollbars - if (window->ScrollbarX) - Scrollbar(ImGuiAxis_X); - if (window->ScrollbarY) - Scrollbar(ImGuiAxis_Y); - - // Render resize grips (after their input handling so we don't have a frame of latency) - if (!(flags & ImGuiWindowFlags_NoResize)) - { - for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) - { - const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; - const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); - window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, grip_draw_size) : ImVec2(grip_draw_size, window_border_size))); - window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(grip_draw_size, window_border_size) : ImVec2(window_border_size, grip_draw_size))); - window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); - window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]); - } - } - - // Borders - RenderWindowOuterBorders(window); - } + RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size); // Draw navigation selection/windowing rectangle border if (g.NavWindowingTargetAnim == window)